package gbench.common.tree;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import java.util.function.Predicate;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.sql.DataSource;

import gbench.common.tree.LittleTree.Term.TermType;

import static gbench.common.tree.LittleTree.IRecord.FIELDS;
import static gbench.common.tree.LittleTree.IRecord.OBJ2SQLTYPE;
import static gbench.common.tree.LittleTree.IRecord.REC;
import static gbench.common.tree.LittleTree.Jdbc.substitute;
import static gbench.common.tree.LittleTree.Json.json2recs;
import static gbench.common.tree.LittleTree.KVPair.KVP;
import static gbench.common.tree.LittleTree.SimpleRecord.REC2;
import static gbench.common.tree.LittleTree.Tuple2.TUP2;
/**
 *
 * @author gbench
 *
 */
public class LittleTree {

    /**
     * 简单的文本读取类：小型文件，可以把文件内容全部读入内存的文件
     * @author gbench
     *
     */
    public static class SimpleFile{

        /**
         * 构造函数
         * 
         * @param path 文件绝对路径
         */
        public SimpleFile(final String path){
            try {
                is = new FileInputStream(path);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }

        /**
         * 文件的输入流
         * 
         * @param is 输入流
         */
        public SimpleFile(final InputStream is) {
            this.is = is;
        }

        /**
         * 读取数据行 读取行数据
         * 
         * @return 行数据流
         */
        public List<String> readlines(){
            return readlines(null);
        }

        /**
         * 读取数据行
         *
         * @param filter 行数据过滤器
         * @return 行数据流
         */
        public List<String> readlines(final Predicate<String> filter){
            BufferedReader br = null;
            List<String> ll = null;
            final Predicate<String> flt = filter==null?(s->true):filter;
            try {
                br = new BufferedReader( new InputStreamReader(is, StandardCharsets.UTF_8) );
                ll = br.lines().filter(flt).collect(Collectors.toList());
            } catch (Exception e) {
                e.printStackTrace();
            }// try

            return ll;
        }

        private InputStream is ; // 输入流
    }

    /**
     * 术语项目
     * @author gbench
     *
     */
    public static class Term{
        /**
         * 字段项目
         * 
         * @param data 自动换项目的字符串序列
         */
        public Term(String data) {
            final List<Predicate<String>> handlers = Arrays.asList(foreach_handler,where_handler,symbol_handler);
            final Iterator<Predicate<String>> itr = handlers.iterator();
            while(itr.hasNext()&&itr.next().test(data));
        }//Term

        /**
         * 符号处理器
         * 
         * @param data 数据字符串
         * @return s->bool 判断谓词
         */
        public Predicate<String> symbol_handler = (final String data) ->{
            final var SYMBOL_PATTERN="\\s*([_$a-z][a-z0-9]*)\\s*";// 符号模式
            final var mat = Pattern.compile(SYMBOL_PATTERN,Pattern.CASE_INSENSITIVE).matcher(data);
            if(mat.find()) {
                this.data = data;
                this.type= TermType.SYMBOL;
                this.pattern = SYMBOL_PATTERN;
                return false;
            }else
                return true;
        };

        /**
         * foreach 的处理
         * 
         * @param data 数据字符串
         * @return s->bool 判断谓词
         */
        public Predicate<String> foreach_handler = (final String data) ->{
            final var FOREACH_PATTERN = "foreach\\s+([a-z_]+)\\s+in\\s+([a-z%-_]+)\\s+(.+)";// foreach 模式
            final var p = Pattern.compile(FOREACH_PATTERN,Pattern.CASE_INSENSITIVE);//%表示字段替换不需要甲引号
            final var m = p.matcher(data.trim());

            if(m.find()) {
                final var loopvar= m.group(1);// 迭代变量
                final var containerName = m.group(2);// 迭代的数据集合用于从 映射对象（map) 中提取循环变量的数据集合
                final var loopbody = m.group(3);// 循环体

                this.foreachTerm = new ForeachTerm(loopvar, containerName, loopbody);
                //System.out.println(loopvar+"==>"+container+"==>"+loopbody);
                final var pat = Pattern.compile(loopvar+"\\s*\\.\\s*"+"([_0-9a-z$]+)",Pattern.CASE_INSENSITIVE);// 注意不区分大消息
                final var matcher = pat.matcher(loopbody);
                while(matcher.find()) {
                    final var placeholder = matcher.group();// 占位符 是由[ 循环变量/loopvar+"."+字段属性名/keyname]二字段来结构的
                    final var keyname = matcher.group(1);// 对应到Record对象中的属性值,也就是占位符在"."之后的部分。
                    this.foreachTerm.add(placeholder, keyname);
                }//while matcher
                this.type = TermType.FOREACH;// 修改类为foreach
                this.data = data;
                this.pattern = loopvar;
                return false;
            }else{// if(m.find)
                return true;
            }//if
        };

        /**
         * 符号处理器
         * 
         * @param data 源数据
         * @return s->bool 判断谓词
         */
        public Predicate<String> where_handler = (final String data) -> {
            final String WHERE_PATTERN = "where\\s+(.+)";// foreach 模式
            final Matcher mat = Pattern.compile(WHERE_PATTERN, Pattern.CASE_INSENSITIVE).matcher(data);
            if (mat.find()) {
                this.data = data;
                this.type = TermType.WHERE;
                this.pattern = WHERE_PATTERN;
                // System.out.println(mat.group(1));
                final var m = Pattern.compile("([^#]+)\\s*#\\s*([a-z]+)([^a-z_]+)\\s*").matcher(mat.group(1));

                this.whereTerm = new WhereTerm();
                this.whereTerm.setData(data);
                while (m.find()) {
                    this.whereTerm.add(m.group(1), m.group(2), m.group(3));
                }

                return false; // 不再进行处理
            } else
                return true;
        };

        /**
         * 符号项目
         * 
         * @return 符号
         */
        public String getSymbol() {
            return this.getType() == TermType.SYMBOL ? data : null;
        }

        /**
         * 符号项目
         * 
         * @return 项类型
         */
        public TermType getType() {
            return type;
        }

        /**
         * foreach 字符串
         * 
         * @param map 符号值列表
         * @return foreach的字符串
         */
        public String toForeachString(final Map<String, Object> map) {
            return this.foreachTerm != null ? this.foreachTerm.toString(map) : null;
        }

        /**
         * where 字符串
         * 
         * @param map 符号值列表
         * @return foreach的字符串
         */
        public String toWhereString(Map<String, Object> map) {
            return this.whereTerm != null ? this.whereTerm.toString(map) : null;
        }

        /**
         * 字符串
         */
        public String toString() {
            return this.data;
        }
        
        /**
         * fill_template 的别名<br>
         * 把template中的占位符用rec中对应名称key的值value给予替换,默认 非null值会用 单引号'括起来，<br>
         * 对于使用$开头/结尾的占位符,比如$name或name$等不采用单引号括起来。<br>
         * 还有对于 数值类型的值value不论占位符/key是否以$开头或结尾都不会用单引号括起来 。<br>
         * 例如 : FT("insert into tblname$ (name,sex) values
         * (#name,#sex)",REC("tblname$","user","#name","张三","#sex","男")) <br>
         * 返回: insert into user (name,sex) values ('张三','男') <br>
         * 
         * @param template           模版字符串
         * @param placeholder2values 关键词列表:占位符/key以及与之对应的值value集合
         * @return 把template中的占位符/key用placeholder2values中的值value给予替换
         */
        public static String FT(final String template, final IRecord placeholder2values) {
            return fill_template(template,placeholder2values);
        }
        
        /**
         * 把template中的占位符用rec中对应名称key的值value给予替换,默认 非null值会用 单引号'括起来，<br>
         * 对于使用$开头/结尾的占位符,比如$name或name$等不采用单引号括起来,<br>
         * 还有对于 数值类型的值value不论占位符/key是否以$开头或结尾都不会用单引号括起来 。<br>
         * 例如 : fill_template("insert into tblname$ (name,sex) values
         * (#name,#sex)",REC("tblname$","user","#name","张三","#sex","男")) <br>
         * 返回: insert into user (name,sex) values ('张三','男') <br>
         * 
         * @param template           模版字符串
         * @param placeholder2values 关键词列表:占位符/key以及与之对应的值value集合
         * @return 把template中的占位符/key用placeholder2values中的值value给予替换
         */
        public static String fill_template(final String template, final IRecord placeholder2values) {
            final var len = template.length(); // 模版的长度
            final StringBuilder buffer = new StringBuilder();// 工作缓存
            final var keys = placeholder2values.keys().stream().sorted((a,b)->-(a.length()-b.length())) // 按照从长到短的顺序进行排序。以保证keys的匹配算法采用的是贪婪算法。
                .collect(Collectors.toList());// 键名 也就是template中的占位符号。 
            final var firstCharMap = keys.stream().collect(Collectors.groupingBy(key-> key.charAt(0)));// keys的首字符集合，这是为了加快 读取的步进速度
            int i = 0;// 当前读取的模版字符位置,从0开始。
            
            while(i<len) {// 从前向后[0,len)的依次读取模板字符串的各个字符
                // 注意:substring(0,0) 或是 substring(x,x) 返回的是一个长度为0的字符串 "",
                // 特别是,当 x大于等于字符串length会抛异常:StringIndexOutOfBoundsException
                final var line = template.substring(0,i);// 业已读过的模版字符串内容[0,i),当前所在位置为i等于line.length
                String placeholder = null;// 占位符号 的内容
                final var kk = firstCharMap.get(template.charAt(i));// 以 i为首字符开头的keys
                if( kk!=null ) {// 使用firstCharMap加速步进速度读取模版字符串
                    for(final var key:kk ) {// 寻找 可以被替换的key
                        final var endIndex = line.length()+key.length(); // 终点索引 exclusive
                        final var b = endIndex > len // 是否匹配到placeholder
                            ? false // 拼装的组合串(line+key) 超长（超过模板串的长度)
                            : template.substring(line.length(), endIndex).equals(key); // 当前位置之后刚好存在一个key模样的字符串
                        if(b) { // 定位到一个完整的占位符：长度合适（endIndex<=len) && 内容匹配 equals
                            placeholder = key; // 提取key作为占位符
                            break; // 确定了占位符 ,跳出本次i位置的kk循环。
                        }// if b 定位到一个完整的占位符
                    }//for key:kk
                }//if kk!=null 
                
                if (placeholder != null) {// 已经发现了占位符号，用rec中的值给予替换
                    boolean isnumberic = false;// 默认不是数字格式
                    final var value = placeholder2values.get(placeholder); // 提取占位符内容
                    if (placeholder.startsWith("$") || placeholder.endsWith("$")) isnumberic = true; // value 是否是 强制 使用 数字格式，即用$作为前/后缀。
                    if (value instanceof Number) isnumberic = true; // 如果值是数字类型就一定会不加引号的。即采用数字格式
                    
                    buffer.append((isnumberic || value == null) ? value + "" : "'" + value + "'"); // 为字符串添加引号，数字格式或是null不加引号
                    i += placeholder.length();// 步进placeholder的长度，跳着前进
                } else {// 发现了占位符号则附加当前的位置的。字符
                    buffer.append(template.charAt(i));
                    i++;// 后移一步
                } // if placeholder
            }// while
            
            return buffer.toString(); // 返回替换后的结果值
        }
        
        /**
         * 清理line <br>
         * 把 含有%符号的line 如 :<br>
         * update t_student set %'id'=437, %'name'='张三', %'sex'='男',%'address'='上海市徐汇区' where code=234 <br>
         * 转换成 <br>
         * update t_student set id=437, name='张三', sex='男', address='上海市徐汇区' where code=234 <br>
         * 
         * @param final_line 待处理的line
         * @return 清理后的line
         */
        public static String percent_tidyline(final String final_line) {
            final var pattern = "%'([^']+)'";// 对%号的标记进行去除单引号
            var line = final_line;// 行数据。
            var matcher = Pattern.compile(pattern).matcher(line); // 匹配器
            while (matcher.find()) {
                final var grp = matcher.group(1);// 提取括号内的内容
                line = matcher.replaceFirst(grp);// 去除掉单引号'构成的括号('...')。
                matcher = Pattern.compile(pattern).matcher(line); // 重定义匹配器
            } // while
            return line; // 返回结果。
        }

        public enum TermType{SYMBOL,FOREACH,WHERE}// 语句项

        /**
         * 条件表达式
         * @author gbench
         *
         */
        public static class WhereTerm{
            
            /**
             * 增加一个项目
             * 
             * @param key     键名
             * @param value   键值
             * @param postfix 后缀,即剩余的其他部分
             */
            void add(final String key, final String value, final String postfix) {
                tuples.add(new Tuple3<>(key, value, postfix));
            }

            /**
             * SQL语句格式化输出
             * 
             * @param map 参数列表 key->value
             * @return 字符换
             */
            public String toString(final Map<String, Object> map) {
                final StringBuffer buffer = new StringBuffer();
                final Stream<Tuple3<String, String, String>> stream = this.tuples.stream();
                // System.out.println(this.data);
                final Function<Object, List<Tuple2<String, Object>>> variables = (oo) -> { // 提取环境变量
                    final List<Tuple2<String, Object>> vars = new LinkedList<>();
                    if (oo != null) {
                        if (oo instanceof IRecord) oo = ((IRecord) oo).toMap(); // 把 IRecord 对象转换成Map结构,注意此处 不能与线面的if组合成elseif
                        
                        if (oo instanceof Collection) { // 不要写成elseif
                            @SuppressWarnings("unchecked")
                            final Collection<Object> coll = (Collection<Object>) oo;
                            coll.forEach(o -> {
                                if (o instanceof String) vars.add(new Tuple2<>(o + "", o));
                            });
                        } else if (oo.getClass().isArray()) {
                            assert oo instanceof Object[];
                            Object[] aa = (Object[]) oo;
                            for (Object a : aa) vars.add(new Tuple2<>(a + "", a));
                        } else if (oo instanceof Map) {
                            final Map<?, ?> aa = (Map<?, ?>) oo;
                            vars.addAll(aa.entrySet().stream()
                                    .map(e -> new Tuple2<String, Object>(e.getKey() + "", e.getValue()))
                                    .collect(Collectors.toList()));
                        } else {
                            vars.add(new Tuple2<>(oo + "", oo));
                        } // if
                    } // if oo
                    return vars;
                };

                stream.forEach(tuple->{
                    String line = "";
                    Object oo = map.get(tuple._2());// 获取字段并展开字段项目
                    String func_name =""; // 函数名称
                    String prefix = ""; // 前缀字符串
                    Matcher mat = Pattern.compile("([a-z_]+)\\s*$").matcher(tuple._1());
                    if(!mat.find())return;
                    func_name = mat.group(1);// 获得关键词：函数名
                    prefix = tuple._1().substring(0,tuple._1().lastIndexOf(func_name)); // 把函数名之前的部分作为 前缀字符串
                    if("and_null".equalsIgnoreCase(func_name)) {
                        line = JOIN(MAP(variables.apply(oo),o->o._1()+" is null")," AND ");
                    }else if("and_notnull".equalsIgnoreCase(func_name)) {
                        line = JOIN(MAP(variables.apply(oo),o->o._1()+" is not null")," AND ");
                    }else if("or_notnull".equalsIgnoreCase(func_name)) {
                        line = JOIN(MAP(variables.apply(oo),o->o._1()+" is not null")," OR ");
                    }else if("and_in".equalsIgnoreCase(func_name)) {
                        line = JOIN(MAP(variables.apply(oo),o->o._1()+" not in "+tuple._2)," AND ");
                    }else if("and_not_in".equalsIgnoreCase(func_name)) {
                        line = JOIN(MAP(variables.apply(oo),o->o._1()+" not in "+tuple._2)," AND ");
                    }else if("and_equals".equalsIgnoreCase(func_name)) {
                        line = JOIN(MAP(variables.apply(oo),o->o._1().replaceAll("##","")+" = "+
                            (((o._1()+"")).startsWith("##")? o._2() :
                                "'"+o._2()+"'"))," AND ");
                    }//if

                    buffer.append(prefix).append(line).append(tuple._3);
                });

                return buffer.length() <= 0 ? "" : "where " + buffer.toString();
            }

            /**
             * 原来的数据文本
             * 
             * @return 数据文本
             */
            public String getData() {
                return data;
            }

            /**
             * 设置 数据文本
             * 
             * @param data 数据文本
             * @return WhereTerm 对象本省方便实现 链式编程
             */
            public WhereTerm setData(String data) {
                this.data = data;
                return this;
            }

            private String data = null; // 数据文本
            private final List<Tuple3<String,String,String>> tuples = new LinkedList<>(); // 数据项目 {键名,键值,后缀}
        }

        /**
         * Foreach Term的结构处理
         * @author gbench
         */
        static class ForeachTerm {

            /**
             * 构建foreach 结构
             * @param loopvar 循环变量
             * @param entriesName 循环体容器
             * @param loopbody 循环体
             */
            ForeachTerm(String loopvar,String entriesName,String loopbody){
                this.loopvar = loopvar;
                this.entriesName = entriesName;
                this.loopbody = loopbody;
            }

            /**
             * 添加一个占位符并指定与其对应的键值
             * @param placeholder 占位符号
             * @param keyname 字段的键名
             */
            public void add(String placeholder,String keyname) {
                kvs.add(new KVPair<>(placeholder, keyname));
            }

            /**
             * 获得循环变量
             * @return 循环变量
             */
            public String getLoopvar() {
                return loopvar;
            }

            /**
             * 设置循环变量（占位符）
             * @param loopvar 设置循环变量（占位符）
             */
            public void setLoopvar(String loopvar) {
                this.loopvar = loopvar;
            }

            /**
             * 获得容器对象的名称：用于从 映射对象（map) 中提取循环变量的数据集合
             * @return 获得容器对象的名称
             */
            public String getEntriesName() {
                return entriesName;
            }

            /**
             * 设置容器对象的名称：用于从 映射对象（map) 中提取循环变量的数据集合
             * @param entriesName 容器对象的名称
             */
            public void setEntriesName(String entriesName) {
                this.entriesName = entriesName;
            }

            /**
             * 获得键值名称
             * @return 占位符与容器元素之间的对应名称。  （占位符,容器对象中的IRecord的键名）
             */
            public List<KVPair<String, String>> getKvs() {
                return kvs;
            }

            /**
             * 设置键值对儿。
             * @param kvs 占位符与容器元素之间的对应名称。  （占位符,容器对象中的IRecord的键名）
             */
            public void setKvs(List<KVPair<String, String>> kvs) {
                this.kvs = kvs;
            }
            
            /**
             * 注意 map 值中的字符需要需要先转移化后传入,如果 值的字符串标记 仅仅会 在收尾 增加一个 单引号"'"+v+"'".<br>
             * 对于 以$字符结尾的key比如 amount$,,值被视为 数值类型，不予添加引号。<br>
             * @param map 映射对象:变量名与变量值的映射集合,其中包含一个 entriesName的缩影定义的一个KVP,用于代表循环变量。
             * @return 使用map对模版字符串进行替换
             */
            @SuppressWarnings("unchecked")
            public String toString(final Map<String,Object> map) {

                List<IRecord> recordEntries = null;
                final String foreachExpr = "foreach "+this.loopvar+" in "+" "+this.entriesName+" "+this.loopbody;// foreach 的源代码表达式
                
                try{
                    final Object entriesObject = map.get(this.getEntriesName());// 提取数据集合
                    if(entriesObject==null)return foreachExpr;
                    final Class<?>entriesCls = entriesObject.getClass();
                    if( entriesObject instanceof Collection || entriesCls.isArray() ) {
                        final Collection<Object> entries = entriesCls.isArray()
                            ? Arrays.asList((Object[])entriesObject)
                            : (Collection<Object>) entriesObject;
                        if( entries.size()>0 ) {// 集合类非空
                            final var opt = entries.stream().filter(entry->!(entry instanceof IRecord)).findAny(); // 是否存在非 IRecord元素
                            
                            if(opt.isPresent()) {// 尝试给予人工修复
                                //System.out.println("List中含有非IRecord对象"+oo);
                                map.put( this.getEntriesName(), entries.stream()
                                    .map( entry -> {// 在kvs增加占位符placeholder->键名keyname之间的对应关系
                                        if(entry instanceof IRecord) {
                                            return entry;
                                        }else{
                                            //特别注意对于非IRecord数据placeholder与keyname一样都等于循环变量
                                            final var placeholder = loopvar; // 占位符
                                            final var key = loopvar; // 值key
                                            kvs.add(new KVPair<>(placeholder, key));//
                                            // 转为IRecord对象，仅有一个以 循环变量名 loopvar 作为键名 key 的IRecord元素
                                            return REC(key,entry);// 这里的loopvar代表 值key 
                                        }// if
                                    }).collect(Collectors.toList()) );// put
                            }// 尝试给予人工修复
                        }else {
                            System.out.println( this.getEntriesName() + " 为 空list");
                            return foreachExpr;
                        }//if
                    }//if
                    recordEntries = REC(map).lla(this.getEntriesName(),IRecord.class);// 使用IRecord提取列表数据,可以有智能转换功能
                }catch(Exception e) {
                    e.printStackTrace();
                }
                
                if(recordEntries == null) return foreachExpr; // 直接返回foreach表达式
                
                final var kvsrec = IRecord.KVS2REC(kvs);// placeholder --> 值key 的映射。
                
                // 返回结果
                final var line = recordEntries.stream().map( rec -> { // 利用循环填充 loopbody 使之形成 实例化 sql语句。
                    
                    final var placeholder2values = kvsrec.aov2rec((Function<String, Object>) rec::get);// 占位符与其值的对应关系。
                    final var b = true; // 模版填充的方法模式选择
                    return b // 模版填充
                        ? Term.fill_template(loopbody, placeholder2values) // 较快的算法。
                        : tokenize(loopbody,placeholder2values.keys()).stream() // 分词
                        .map( token -> token.bool("flag") // 是否为关键字(占位符)
                            ? placeholder2values.get( token.str("name"), v -> // 关键字(占位符)的值替换
                                token.str("name").endsWith("$")|| v instanceof Number  // 数字类型的 值
                                ? v // 数字类型的值
                                : ( v==null ? null : "'"+v+"'" ) // 提取数字类型的值
                              )+"" // 替换关键词(占位符)为具体的值
                            : token.str("name") // 模版字符
                        ).collect(Collectors.joining());// 模版的填充
                    
                }).collect(Collectors.joining(", ")); // recordEntries 返回结果
                
                return percent_tidyline(line);// 对百分号进行转义
                
            }// toString

            /**
             * 一个 foreach 结构是这样的形式：
             * foreach loopvar in container loopbody
             * 其中 在 loopody 会出现 placeholder,placeholder 一般是 loopvar+"."+keyname
             * 但这并不是一定的。比如对于非IRecord的集合数据，loopvar可以干脆就是keyname
             * keyname对应到具体的字段名称。这样我们就可以根据字段名称给予获取具体的值了。
             * placeholder 用于在替换循环体中的数值信息。
             *
             * 写几个例子:
             * foreach u in user (user.name,user.password):
             * ----------------------------------------------
             * placeholder          keyname
             * user.name            path
             * user.password        password 
             * kvs:user.name->path,user.password->password
             *
             * foreach u in user u:
             * --------------------------------------------
             * placeholder          keyname
             * u                    u
             * kvs:u->u
             */
            private String loopvar;// 循环变量名
            private String entriesName;// 循环容器的名称，也就一个List的对象集合(一般为IRecord对象)
            private final String loopbody;//循环体
            private List<KVPair<String,String>> kvs = new LinkedList<>(); // e.name->name : placeholder 与  值(IRecord)中的key的对应。
        }//ForeachTerm

        /**
         * 返回模式
         * @return 返回模式
         */
        public String getPattern() {
            return pattern;
        }

        private String data;// 字段项目的字符串序列
        private TermType type; // 字段项目类型,简单符号 还是foreach结构
        private ForeachTerm foreachTerm = null;// forEach 字段项目
        private WhereTerm whereTerm = null;
        private String pattern = null;// 模式

        public final static String TERM_PATTERN = "\\$?\\s*\\{([^\\{\\}]+)\\}";
    }

    /**
     * 命名SQL语句对象，每个SQL都有一个名字
     * 含有模板参数(unix风格和mybatis风格) #variable ${variable}
     * 占位符即模板参数式样：#xxx 字符串类型, ##xxx 数值类型,或是 ${xxx}
     * 一个SQL对象包含有：
     * 名称:name，一个sql模板数据,
     * 模板:sqltpl， sql语句模板或者框架，含有必要的参数，参数可以有sqlctx来提供 或者个与计算生成。参数采用 #xxx 字符串类型, ##xxx 数值类型,或是 ${xxx} 字符串结尾会添加换行符号类型  来进行占位,其中
     *  语句上下文：sqlctx 一系列的环境参数，参数蚕蛹键值对的形式 在sqlctx 以IRecord为单位进行存放。 sqlctx 是一个IRecord 集合用来表示多组数据，比如：插入语句 的多条数据记录。
     * 
     * @author gbench
     */
    public static class SQL{

        /**
         * 这是一个查询语句
         * @param name 语句名称
         * @param sqltpl 查询语句，参数采用 #xxx 字符串类型, ##xxx 数值类型,或是 ${xxx} 字符串结尾会添加换行符号类型  来进行占位,其中
         */
        public SQL(final String name,final String sqltpl) {
            this.name = name;
            this.sqltpl = sqltpl;
        }
        
        /**
         * 这是一个查询语句
         * @param name 语句名称
         * @param sqltpl 查询语句，参数采用 #xxx 字符串类型, ##xxx 数值类型,或是 ${xxx} 字符串结尾会添加换行符号类型  来进行占位,其中
         * @param recs 参数列表
         */
        public SQL(final String name,final String sqltpl,final IRecord ... recs) {
            this.name = name;
            this.sqltpl = sqltpl;
            this.sqlctx = Arrays.asList(recs);
        }

        /**
         * 命名SQL语句对象，每个SQL都有一个名字
         * @param name SQL语句的名，可以是文本字符串，由于标识SQL，便于检索
         * @param rec SQL 语句的上下文数据：比如插入的操作的 插入记录
         */
        public SQL(final String name,IRecord rec) {
            this.name = name;
            this.sqlctx = Collections.singletonList(rec);// 保证sqlctx为一个记录集合
        }
        
        /**
         * 命名SQL语句对象，每个SQL都有一个名字
         * @param name SQL语句的名，可以是文本字符串，由于标识SQL，便于检索
         */
        public SQL(final String name) {
            this.name = name;
            this.sqlctx = Collections.singletonList((IRecord) null);// 行数据
        }

        /**
         * 命名SQL语句对象，每个SQL都有一个名字
         * @param name SQL语句的名，可以是文本字符串，由于标识SQL，便于检索
         * @param sqlctx 行数据，SQL 语句的上下文数据：比如插入的操作的，插入记录
         */
        public SQL(final String name,final List<IRecord> sqlctx) {
            this.name = name;
            this.sqlctx = sqlctx;
        }
        
        /**
         * 语句的名字
         * 
         * @return 语句的名字
         */
        public String name() {
            return this.name;
        }

        /**
         * 查询语句：直接放回sqltpl
         * 
         * @return 文本串
         */
        public String string() {
            return this.sqltpl;
        }

        /**
         * 查询语句<br>
         * 使用getSqlCtxAsOneRecord 格式化输出
         * 
         * @return 文本串
         */
        public String string2() {
            return this.string(this.getSqlCtxAsOneRecord());
        }

        /**
         *  数据查询:这里关于 字符转义的描述很有问题，有时间的是需要要补充 <br>
         *  带有变量值的语句内容
         *
         *  变量的替换规则如下: <br>
         * 1、#便开头的变量 使用 单引号进行包被 <br>
         * 2、##开头的变量不是使用单引号包被 <br>
         * 3、${foreach id in ids id } 为单值形式foreach 结构。ids为单值列表 <br>
         * 4、${foreach fld in kvset %fld.name=fld.value} 为复合值形式的列表,kvset为集合列表， <br>
         *      列表中每个元素为 字段记录,每个字段属性有name,和value <br>
         *      如果以%开头，会根据替换值的类型智能判断是否添加单引号：为数字不加单引号，否则加上单引号 <br>
         * 由于 rec 中的值可能会被加上单引号，所以转义字符需要进行手动给予转换完成。以此保证语法合理性。
         * 5、如果占位符以$结尾则则视该值为数字，即不加引号：此种标识为为强制转换为数字，<br>
         * 而不管该字段是否是真的为为数字类型，即使是字符串也不加引号。会覆盖掉%的规则
         * <br>
         * 例子：
         * kvset 中的字段标识符的 正则表达式的格式为：[_0-9a-z\\$]+,即java 中标识符的规则。 <br>
         * 其中以$结尾的字段一般用于标识这是一个数字类型的字段。<br>
         * 1、List<IRecord> kvset = Arrays.asList( <br>
         *       REC2("name","id","value",437), <br>
         *       REC2("name","name","value","张三"), <br>
         *       REC2("name","sex","value","男"), <br>
         *       REC2("name","address","value","上海市徐汇区") ); <br>
         *    IRecord rec = REC2("kvset",kvset,"code",98) <br>
         *  update t_student set ${ foreach fld in kvset %fld.name=fld.value} where code=#code <br>
         *     生成：update t_student set id=437, name='张三', sex='男', address='上海市徐汇区'  where code='98' <br>
         * <br>
         * 注意： <br>
         *     若是kvset中的  是这样的结构：注意kvset中的value$,有一个'$'后缀,于是fld.value$ 就会被视作数字：而不管它是否真的是数字了，<br>
         *     即$是强制为数字额形式来显示（去除单引号） <br>
         *     final var kvset = Arrays.asList( // 数据列表 <br>
         *           REC2("name", "id", "value$", 437), <br>
         *           REC2("name", "name", "value$", "张三"), <br>
         *           REC2("name", "sex", "value$", "男"), <br>
         *           REC2("name", "address", "value$", "上海市徐汇区") <br>
         *       );// kvset <br>
         *       update t_student set ${ foreach fld in kvset %fld.name=fld.value$ } where code=##code <br>
         *        生成update t_student set id=437, name=张三, sex=男, address=上海市徐汇区  where code=98 <br>
         *       请注意：##code是用于非foreach结构的数字类型的显示方法，而fld.value$是专用于foreach 结构的强制显示为数字的方法。<br>
         *
         * 2、IRecord rec = REC2("users",Arrays.asList(1,2,3,4)) <br>
         *   select * from t_student where id in (${ foreach id in users id } ) <br>
         *   生成: select * from t_student where id in (1, 2, 3, 4  ) <br>
         *
         * 3、IRecord rec = REC2("users",Arrays.asList("1,2,3,4".split(","))) <br>
         *   select * from t_student where id in ( ${ foreach id in users id } ) <br>
         *   生成: select * from t_student where id in ('1', '2', '3', '4'  ) <br>
         *
         * @param rec 被替换数据的 键值对
         * @return 替换后的sql语句。
         */
        public String string(final IRecord rec) {
            if (rec == null) return this.string();
            return this.string(rec.toMap());
        }

        /**
         * 带有变量值的语句内容。 用map中的值数据替换掉 sql模板语句的内容。
         * 
         * @param map 变量的名与值的集合
         * @return SQL语句
         */
        public String string(final Map<String, Object> map) {
            String s= this.string();
            final Function<Object,String> escape = (obj)->(obj+"").replace("(", "\\(").replace(")","\\)").replace("$","\\$");
            for(Term term:this.terms()) { 
                //try {// 确保出现错误依旧可以运行
                    if(term.getType() == TermType.SYMBOL) {// 记录符号
                        Object obj = map.get(term.getSymbol());
                        String v = (obj+"").replace("$", "\\$");// 转义$符号
                        if(!v.matches("[.\\d]+"))v=v.replace(".", "\\.");// 如果不是字符进行。转义
                        //  System.out.println(v); // 测试数据模式
                        if(v==null)continue; // 空值不予处理
                        s=s.replaceAll("\\$?\\s*\\{\\s*"+term+"\\s*}","'"+v+"'");
                        s=s.replaceAll("##"+term,v+"");// 使用双#号表示为数字不需要用括号括起来
                        s=s.replaceAll("#"+term,"'"+v+"'");// 使用单警号表示是字符串需要采用括号括起来
                    }else if(term.getType() == TermType.FOREACH) {// foreach 解析
                        Object t = term.toForeachString(map);// 获得term 的替换后的数据
                        if (t==null)continue;
                        String foreach_term="\\$?\\s*\\{\\s*"+escape.apply(term.data)+"\\s*}";// foreach的字符描述
                        s=s.replaceAll(foreach_term,escape.apply(t));
                    }else if(term.getType() == TermType.WHERE) {
                        final Object t = term.toWhereString(map);// 获得term 的替换后的数据
                        if ( t==null ) continue;
                        final String where_term="\\$?\\s*\\{\\s*"+escape.apply(term.data)+"\\s*\\}";// foreach的字符描述
                        s=s.replaceAll(where_term,escape.apply(t));
                    }
                //}catch(Exception e) {e.printStackTrace();}
            }//for

            return s;
        }

        /**
         * 插入一条数据记录到name所在的表中
         * 
         * @param rec 模板命名参数的键值对儿集合：用recB-recA的中的变量来实例化SQL模板，生成一个insert 插入语句
         * @return insert SQL 语句
         */
        public String insert(final IRecord rec) {
            return insert(rec, kv -> kv.value() != null);
        }

        /**
         * 插入数据
         * 
         * @param pfilter 插入的字段过滤器
         * @return insert SQL 语句
         */
        public String insert(final Predicate<KVPair<String, Object>> pfilter) {
            return this.insert(this.sqlctx, pfilter);
        }

        /**
         * 插入数据
         * 
         * @param rec     插入的数据的字段列表，用recB-recA的中的变量来实例化SQL模板，生成一个insert 插入语句
         * @param pfilter 插入的字段过滤器
         * @return insert SQL 语句
         */
        public String insert(final IRecord rec, final Predicate<KVPair<String, Object>> pfilter) {
            final StringBuilder buffer = new StringBuilder();
            final var initialCapacity = 30; // 默认30个字段
            final var flds = new ArrayList<String>(initialCapacity);// 字段列表
            final var vals = new ArrayList<String>(initialCapacity);// 指端值列表 与flds 一一对应 
            Predicate<KVPair<String,Object>> pfiltertmp = pfilter;
            if(pfiltertmp==null)pfiltertmp=(kv)->true;
            final Predicate<KVPair<String,Object>> pft = pfiltertmp;
            final var dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            final var dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            final var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            
            rec.stream().filter(pft) // 删除空值字符串
                .forEach(e->{
                    Object value = e.value();
                    // value 数据类型格式化
                    if( value instanceof LocalDateTime ) {
                        value = LittleTree.MFT("{0}",dtf1.format((LocalDateTime)value));
                    }else if ( value instanceof Date) {
                        value = LittleTree.MFT("{0}",sdf.format((Date)value));
                    }else if( value instanceof LocalTime ) {
                        value = LittleTree.MFT("{0}",dtf1.format((LocalTime)value));
                    }else if(value instanceof LocalDate) {
                        value = LittleTree.MFT("{0}",dtf2.format((LocalDate)value));
                    }else {
                        // do nothing
                    }// if
                    final var fldvalue = LittleTree.MFT("''{0}''",(value+"").replace("'", "\\'")); // 格式化字段值
                    final var fldname = parseFieldName(e.key()).str("name");// 获取字段名
                    final var i = flds.indexOf(fldname);// fldname的索引位置,如果>0 表示业已存在一个同名的字段，需要给予覆盖。
                    if(i<0) {// 字段名不存在
                        flds.add(fldname);
                        vals.add(fldvalue);
                    }else { // 覆盖原先的字段与字段值
                        vals.set(i,fldvalue); // 覆盖对应位置的字段值。
                    }// if
                });// forEach
            
            buffer.append("insert into ").append(this.name).append(" (");
            buffer.append(String.join(",", flds));
            buffer.append(") values (");
            buffer.append(String.join(",", vals));
            buffer.append(")");
            return buffer.toString();
        }

        /**
         * 插入数据
         * 
         * @param recs    插入的数据的字段列表，用recB-recA的中的变量来实例化SQL模板，生成一个insert 插入语句
         * @param pfilter 插入的字段过滤器
         * @return insert SQL 语句
         */
        public String insert(final List<IRecord> recs, final Predicate<KVPair<String, Object>> pfilter) {
            return recs.stream().map(rec->this.insert(rec,pfilter))
                .collect(Collectors.joining(";\n"));
        }

        /**
         * 生成insert 插入语句
         * 
         * @return insert 插入语句
         */
        public String insert() {
            final var line = this.insert(this.sqlctx,kv->kv.value()!=null);
            return line.endsWith(";")?line:(line+";");
        }

        /**
         * 字段信息扩展
         * 
         * @param recB 覆盖到本字段信息的数据记录
         * @return 字段信息扩展
         */
        public IRecord extend(final IRecord recB) {
            if (this.sqlctx.size() <= 0) return recB.duplicate();
            IRecord recA = this.getSqlCtxAsOneRecord();
            return SimpleRecord.extend(recA, recB);
        }

        /**
         * 注意：不能把id 设置成null
         *
         * 使用 recB 去更新 recA
         * 
         * @param recA  老数据
         * @param recB  新数据，用recB-recA的中的变量来实例化SQL模板，生成一个update语句
         * @param which 更新范围,IRecord 解构个字段采用and 进行过滤,String 类型直接拼接到 update 语句结尾
         * @return 更新的sql语句
         */
        public String update(IRecord recA, IRecord recB, Object which) {
            StringBuilder buffer = new StringBuilder();
            buffer.append("update ").append(this.name());

            if(recA==null)recA = new SimpleRecord();
            if(recB==null)recB = new SimpleRecord();
            
            recA = REC(recA.applyOnkeys(k->parseFieldName(k).str("name")));
            final var rec = SimpleRecord.REC2(); // 使用SimpleRecord 以保证可以存放null 值
            recB.foreach((k,v)->{
                final var key = parseFieldName(k).get("name");
                rec.add(key,v);
            });
            recB = rec;

            List<String> keys = recA.kvs().stream()
                .map(KVPair::key).collect(Collectors.toList());
            keys.addAll(recB.kvs().stream()
                .map(KVPair::key).collect(Collectors.toList()));
            keys = keys.stream().distinct().collect(Collectors.toList());
            final var kvs = new
                LinkedList<KVPair<String,Object>>();// 键值对
            //System.out.println("全量的更新键值表："+keys);
            for(String key:keys) {
                Object oA = recA.get(key);
                Object oB = recB.get(key);
                if(oA!=null && oB!=null && oA.equals(oB)) continue; // 值相同不予更新
                if(recB.has(key) && recA.has(key)) {
                    kvs.add(new KVPair<>(key, oB));
                }//if
            }//for

            if(kvs.size()>0) {
                buffer.append(" set ");
                // 字段修改 set field = value
                buffer.append(kvs.stream()
                    .filter(kv-> !"id".equals(kv.key()) || kv.value() != null) // 过滤掉id==null 的键值
                    .map(e->e.key()+"="+MFT(e.value()==null?"null":"''{0}''",e.value()))
                    .collect(Collectors.joining(",")));
            }//if kvs.size()>0

            // 指定更新范围
            if(which!=null && which instanceof IRecord) {
                String filter = ((IRecord)which).kvs().stream()
                    .map(e->e.key()+"='"+e.value()+"'")
                    .collect(Collectors.joining(" and "));
                buffer.append(" where ").append(filter);
            }else if(which!=null && which instanceof String) {
                buffer.append(" where ").append(which);
            }else if(which==null && recA.get("id")!=null) {// 默认更新id
                buffer.append(" where id='").append(recA.get("id")).append("'");
            }//if which!=null

            return buffer.toString();
        }

        /**
         * 更新语句
         *
         * @param newData  新数据，用 newData的中的变量来实例化SQL模板，生成一个update语句
         * @param whichone 更新范围, 可以是 IRecord 或 String IRecord 解构每个字段采用and 进行过滤, String
         *                 类型直接拼接到 update 语句结尾
         * @return 更新后的sql 语句
         */
        public String update(IRecord newData, Object whichone) {
            return this.update(this.getSqlCtxAsOneRecord(), newData, whichone);
        }
        
        /**
         * 把sqlctx 合并成一个IRecord 以获得完整的keys 列表
         * 
         * @return IRecord
         */
        public IRecord getSqlCtxAsOneRecord() {
            final var rec = REC();
            this.sqlctx.forEach(rec::add);
            return rec;
        }
        
        /**
         * 把sqlctx中的数据拼装成一个update 语句 <br>
         * SQL.of("user",REC("id",1,"name","张三")).update("id") <br>
         * 生成 update user set name='张三' where id='1'
         * 
         * @param ids 用作过滤条件的 字段名称 ,比如 <br>
         * @return update 语句
         */
        public String update2(String... ids) {
            final var newData = this.getSqlCtxAsOneRecord();
            final var ss = Arrays.asList(ids);
            final var empty = IRecord.builder(newData.filter(kvp -> !ss.contains(kvp._1()))).get(UUID.randomUUID());
            return this.update(empty, newData, newData.filter(ids));
        }
        
        /**
         * 把sqlctx中的数据拼装成一个update 语句 ids 默认为 id
         * 
         * @return update 语句
         */
        public String update2() {
            return this.update2("id");
        }

        /**
         * 更新语句:update all
         *
         * @param newData 新数据 用 newData的中的变量来实例化SQL模板，生成一个update语句
         * @return 更新数据的sql
         */
        public String update(IRecord newData) {
            return this.update(this.getSqlCtxAsOneRecord(),newData,null);
        }
        
        /**
         * 根据字段的数据类型进行表定义，这个函数不建议在生产环境中使用。<br>
         * 仅用于原型开发时快速测试使用 <br>
         * 对于以数字开始的字段名例如: "123abc" 会被视为  abc的字段名 ,该字段的类型长度为 123<br>
         * 对于以#开头的字段名视为主键约束  比如:"#id" <br>
         * 对于以~开头的字段名视为唯一约束  比如:"~name" 表示 添加唯一性约束<br>
         * 比如:"~32name" 表示 添加唯一性约束,字符长度为32<br>
         * intkey_autocrement 默认为 false , 即 对于int 类型的key 不予添加自增长 
         * 
         * @return [ <br>
         *  0:drop table, <br>
         *  1:drop table if exists & create, <br>
         *  2:create, <br>
         *  3:primarykey (当为单值主键的时候  主键约束会直接写入  字段定义之中,  索引3就变成了唯一约束了,后续的项目也会提前), <br>
         *  4:unique constraints <br>
         *  ],3和4 根据record设置 可能包含。 <br>
         */
        public List<String> createTable() {
            return this.createTable(false);
        }

        /**
         * 根据字段的数据类型进行表定义，这个函数不建议在生产环境中使用。<br>
         * 仅用于原型开发时快速测试使用 <br>
         * 对于以数字开始的字段名例如: "123abc" 会被视为  abc的字段名 ,该字段的类型长度为 123<br>
         * 对于以#开头的字段名视为主键约束  比如:"#id" <br>
         * 对于以~开头的字段名视为唯一约束  比如:"~name" 表示 添加唯一性约束<br>
         * 比如:"~32name" 表示 添加唯一性约束,字符长度为32<br>
         * 
         * @param intkey_autocrement 对于int 类型的key 是否增加自增长
         * @return [ <br>
         *  0:drop table, <br>
         *  1:drop table if exists & create, <br>
         *  2:create, <br>
         *  3:primarykey (当为单值主键的时候  主键约束会直接写入  字段定义之中,  索引3就变成了唯一约束了,后续的项目也会提前), <br>
         *  4:unique constraints <br>
         *  ],3和4 根据record设置 可能包含。 <br>
         */
        public List<String> createTable(final boolean intkey_autocrement) {
            final List<String> sqls = new LinkedList<>();// sql 语句集合
            final StringBuilder buffer = new StringBuilder();
            
            buffer.append("-- -----------------------------------\n");
            buffer.append("-- #").append(name).append("\n");
            buffer.append("-- author:gbench/").append(new SimpleDateFormat(
                    "yyyy-MM-dd HH:mm:ss").format(new Date())).append("\n");
            buffer.append("-- -----------------------------------\n");
            buffer.append("drop table if exists ").append(name).append(";\n");
            sqls.add(buffer.toString());

            final var primaryKeys = new LinkedList<Tuple2<String,String>>(); // 主键列表
            final var uniqueKeys = new LinkedList<String>(); // 主键列表
            final var fldDefs = new LinkedHashMap<String,String>();
            final var tableDefs = REC(); // 表的定义
            this.sqlctx.forEach(tableDefs::add);
            
            tableDefs.stream().forEach(e->{
                final var key = e.key().strip();// 提取主键描述字符串
                final var fldrec = parseFieldName(key);// 接卸字段描述
                final var value = e.value(); // 键值
                final var type = ( ( e.value() == null )
                    ? "varchar(512)" // 默认类型为 字符串
                    : javaType2SqlType( value instanceof Class<?> ? (Class<?>)value : value.getClass(), fldrec.i4("size") ) );
                if( fldrec.bool("primarykey")) primaryKeys.add(TUP2(fldrec.str("name"),type));// 加入主键
                if( fldrec.bool("uniquekey")) uniqueKeys.add(fldrec.str("name"));// 加入唯一性约束
                
                //System.out.println("name"+tup);
                final var line = fldrec.str("name")+" "+type;
                fldDefs.put(fldrec.str("name"),line);
            });// map
            
            final var constraints = new LinkedList<String>(); // 约束的定义
            if(primaryKeys.size()>0) {
                var flag = false;// 是否在行内添加
                if(primaryKeys.size()==1) {
                    final var tup = primaryKeys.getFirst();
                    final var typename = tup._2().toUpperCase();
                    if("INT".equals(typename)||"BIGINT".equals(typename)) {//对于 int key 是否 auto_increment 
                        flag =  true;
                        fldDefs.computeIfPresent(tup._1(), (fldname,def)->MessageFormat.format("{0} {1} {2}",def,
                            intkey_autocrement?"auto_increment":"","primary key"));
                    }//if
                }//if
                if(!flag)constraints.add(MFT("alter table {0} add constraint primary key pk_{0} ({1});",
                    name,primaryKeys.stream().map(e->e._1().toLowerCase()).collect(Collectors.joining(","))));
            }//primaryKeys.size
            
            if(uniqueKeys.size()>0) {// 唯一约束
                constraints.add(MFT("alter table {0} add constraint unique uq_{0} ({1});",
                    name.toLowerCase(), String.join(",", uniqueKeys)));
            }
            final var flds = String.join(",\n\t", fldDefs.values());
            
            buffer.append("create table ").append(name).append("(\n\t");
            buffer.append(flds);
            buffer.append("\n) ");
            buffer.append(" comment '").append(name).append("';");
            sqls.add(buffer.toString());
            sqls.add(buffer.substring(sqls.get(0).length()));
            sqls.addAll(constraints);
            
            return sqls;
        }

        /**
         * 获得模板变量
         * 
         * @return 去重了之后的模板变量
         */
        public List<Term> terms() {
            return getAllTerms(sqltpl).stream()
                .distinct()
                .collect(Collectors.toList());
        }

        /**
         * 返回sqlCtx
         * 
         * @return sqlctx
         */
        public List<IRecord> getSqlCtx() {
            return this.sqlctx;
        }

        /**
         * 返回sqlCtx的IRecord 数组
         * 
         * @return IRecord 的数组
         */
        public IRecord[] getSqlCtx2() {
            return this.sqlctx.toArray(IRecord[]::new);
        }

        /**
         * 返回sqltpl
         * 
         * @return sqltpl
         */
        public String getSqlTpl() {
            return this.sqltpl;
        }

        /**
         * 返回名称
         * 
         * @return 名称
         */
        public String getName() {
            return this.name;
        }

        /**
         * 格式化输出:尝试 返回sqltpl,若sqltpl为空则返回insert()语句
         * 
         * @return 数据文本字符串
         */
        public String toString() {
            if(this.string()!=null) {
                return this.string()+(terms().size()<=0?"":"\nterms:"+terms());
            }else {
                return this.insert();
            }
        }

        /**
         * SQL 语句Builder
         * 
         * @author gbench
         *
         */
        public static class Builder {

            /**
             * 构造函数
             * 
             * @param name SQL名称
             */
            public Builder(final String name) {
                this.name = name;
            }

            /**
             * 生成一个SQL语句对象
             * 
             * @param recs sql 上下文集合
             * @return SQL对象
             */
            public SQL get(IRecord... recs) {
                return new SQL(name, Arrays.asList(recs));
            }

            private final String name;// SQL语句的名称
        }

        /**
         * 命名SQL语句对象，每个SQL都有一个名字
         * @param name SQL语句的名，可以是文本字符串，由于标识SQL，便于检索
         * @param recs 行数据，SQL 语句的上下文数据：比如插入的操作的，插入记录
         * @return SQL独享
         */
        public static SQL of(final String name,final IRecord ... recs) {
            return new SQL(name,Arrays.asList(recs));
        }

        /**
         * 命名SQL语句对象，每个SQL都有一个名字
         * @param name SQL语句的名，可以是文本字符串，由于标识SQL，便于检索
         * @param sqltpl sql 模版
         * @param recs 行数据，SQL 语句的上下文数据：比如插入的操作的，插入记录
         * @return SQL独享
         */
        public static SQL of(final String name,final String sqltpl,final IRecord ... recs) {
            return new SQL(name,sqltpl,recs);
        }

        /**
         * 命名SQL语句对象，每个SQL都有一个名字 <br>
         * name SQL语句的任意名称  <br>
         * @param sqltpl sql 模版
         * @param recs 行数据，SQL 语句的上下文数据：比如插入的操作的，插入记录
         * @return SQL独享
         */
        public static SQL nsql(final String sqltpl,final IRecord ... recs) {
            return new SQL(UUID.randomUUID().toString(),sqltpl,recs);
        }

        /**
         * 命名SQL语句对象，每个SQL都有一个名字
         * @param name SQL语句的名，可以是文本字符串，由于标识SQL，便于检索
         * @return SQL独享
         */
        public static Builder builder(final String name) {
            return new Builder(name);
        }

        /**
         * builder 的别名 <br>
         * 命名SQL语句对象，每个SQL都有一个名字
         * 
         * @param name SQL语句的名，可以是文本字符串，由于标识SQL，便于检索
         * @return SQL独享
         */
        public static Builder bd(final String name) {
            return builder(name);
        }

        /**
         * 解析一个SQL字段定义
         * 
         * @param line 字段定义行 <br>
         *             对于以数字开始的字段名例如: "123abc" 会被视为 abc的字段名 ,该字段的类型长度为 123<br>
         *             对于以#开头的字段名视为主键约束 比如:"#id" <br>
         *             对于以~开头的字段名视为唯一约束 比如:"~name" 表示 添加唯一性约束<br>
         *             比如:"~32name" 表示 添加唯一性约束,字符长度为32<br>
         * @return {name:字段名,size:字段size,primarykey:是否为主键约束,"uniquekey",是否为唯一约束}
         */
        public static IRecord parseFieldName(final String line) {
            
            final String FIELD_NAME_PATTERN = "\\s*([-#~!@\\+])?\\s*([\\d]+)?\\s*([a-zA-z].*)\\s*"; // 字段名Pattern
            final var pattern = Pattern.compile(FIELD_NAME_PATTERN);
            final var matcher = pattern.matcher(line);
            
            if (matcher.find()) {
                final var flagstr = matcher.group(1);
                final var sizestr = matcher.group(2);
                final var size = sizestr == null ? null : Integer.parseInt(sizestr);
                final var name = matcher.group(3);
                return REC("size", size, 
                        "name", name, 
                        "primarykey", flagstr != null && flagstr.startsWith("#"),
                        "uniquekey", flagstr != null && flagstr.startsWith("~"));
            } else {
                return REC("name", line);
            } // if
        }

        /**
         * 创建表的sql语句
         * 
         * @param table 表名
         * @param rec   字段定义
         * @param brief 表摘要信息
         * @return 创建表解构
         */
        public static List<String> createTable(final String table, final IRecord rec, final String brief) {
            final var sqls = new LinkedList<String>();
            var buffer = new StringBuffer();
            buffer.append("-- -----------------------------------\n");
            buffer.append("-- #").append(brief).append("\n");
            buffer.append("-- author:gbench/").append(new SimpleDateFormat(
                    "yyyy-MM-dd HH:mm:ss").format(new Date())).append("\n");
            buffer.append("-- -----------------------------------\n");
            buffer.append("drop table if exists ").append(table).append(";\n");
            sqls.add(buffer.toString());
        
            buffer = new StringBuffer();
            buffer.append("create table ").append(table).append("(\n\t");
            String flds = rec.kvs().stream()
                .map(e->e.key()+" "+e.value()+"")
                .collect(Collectors.joining(",\n\t"));
            buffer.append(flds);
            buffer.append("\n)");
            buffer.append(" comment '").append(brief).append("';");
            sqls.add(buffer.toString());
            return sqls;
        }

        /**
         * @param table 表名
         * @param rec   字段定义
         * @return 创建表解构
         */
        public static List<String> createTable(String table, IRecord rec) {
            return createTable(table, rec, table);
        }

        /**
         * 从模板文字中提取文件参数变量
         * 
         * @param line 模板
         * @return 返回变量的次序就是变量在模板中出现测序，并且没有去重
         */
        public static List<Term> getAllTerms(final String line) {
            final List<Term> ll = new LinkedList<>();
            
            if(line!=null)for(final String name:VAR_NAME_PATTERNS) {// 变量名模式
                final Pattern p = Pattern.compile(name);
                final Matcher mat = p.matcher(line);
                while(mat.find())ll.add(new Term(mat.group(1)));
            }//for

            return ll;
        }

        /**
         * javaType转sqlType
         * 
         * @param cls  JAVA类名
         * @param size 类型参数的长度
         * @return 对应于cls的SQL 数据类型
         */
        public static String javaType2SqlType(final Class<?> cls, final Number size){
            
            if( cls.equals(Double.class) 
                || cls.equals(double.class) 
                || cls.equals(Float.class) 
                || cls.equals(float.class) 
                ){
                return "DOUBLE";
            }else if(cls.equals(Boolean.class) ||
                cls.equals(boolean.class) 
                ){
                return "TINYINT";
            }else if(cls.equals(Character.class) ||
                cls.equals(char.class) 
                ){
                return "VARCHAR(12)";// 字节
            }else if( cls.equals(Integer.class)
                || cls.equals(int.class) 
                || cls.equals(Short.class) 
                || cls.equals(short.class) 
                ){
                return "INT";
            }else if( cls.equals(Long.class)
                || cls.equals(long.class) 
                ){
                return "BIGINT";
            }else if( cls.equals(LocalDate.class) 
                ){
                return "DATE";
            }else if( cls.equals(Date.class) 
                || cls.equals(Timestamp.class )
                || cls.equals(LocalDateTime.class )
                || cls.equals(LocalTime.class )
                ){
                return "TIMESTAMP";
            }else{
                return MFT("VARCHAR({0})",size==null?512:size.intValue());
            }
        }

        /**
         * 生成SQL语句: 依赖于字段反射，从obj(pojo)重提取属性数据，给予闯将对应ORM 关系映射里的 数据库表<br>
         * 生成的表名默认为 obj的类名 :obj.getClass()。getSimpleName()
         * 
         * @param obj 待从中提取属性字段数据的javabean
         * @return 生成SQL语句
         */
        public static String DDL_CREATE_TABLE(final Object obj) {
            return DDL_CREATE_TABLE(obj, null);
        }

        /**
         * 生成SQL语句 依赖于字段反射，从obj(pojo)重提取属性数据，给予闯将对应ORM 关系映射里的 数据库表
         * 
         * @param obj 待从中提取属性字段数据的javabean
         * @param name 数据表明
         * @return 生成SQL语句
         */
        public static String DDL_CREATE_TABLE(Object obj, final String name) {
            final Class<?> cls = obj instanceof Class<?> ? (Class<?>)obj:obj.getClass();
            final var tab = name ==null ?cls.getSimpleName():name;
            final var ll = new LinkedList<Tuple2<String,String>>();
            FIELDS(cls).forEach((k,v)->{
                String fld = k;
                String type = OBJ2SQLTYPE(v.getType());
                ll.add(new Tuple2<>(fld, type));
            });
            final var s = "create table if not exists "+tab+" ("+ll.stream().map(e->e._1()+" "+e._2())
                .collect(Collectors.joining(","))+")";
            return s;
        }

        /**
         * 生成SQL语句: <br>
         * 依赖于字段反射，从obj(pojo)重提取属性数据，给予闯将对应ORM 关系映射里的 数据库表 <br>
         * 表名默认为 obj的类名 :obj.getClass()。getSimpleName() <br>
         * 
         * @param obj 待从中提取属性字段数据的javabean
         * @return 删除表的SQL语句
         */
        public static String DDL_DROP_TABLE(final Object obj) {
            return DDL_DROP_TABLE(obj,null);
        }

        /**
         * 生成SQL语句 <br>
         * 依赖于字段反射，从obj(pojo)重提取属性数据，给予闯将对应ORM 关系映射里的 数据库表 <br>
         * 表名默认为 obj的类名 :obj.getClass()。getSimpleName() <br>
         * 
         * @param obj 待从中提取属性字段数据的javabean <br>
         * @param name 表名
         * @return 删除表的SQL语句
         */
        public static String DDL_DROP_TABLE(final Object obj,final String name) {
            final Class<?> cls = obj instanceof Class<?> ? (Class<?>)obj:obj.getClass();
            final var tab = name ==null ?cls.getSimpleName():name;
            return "drop table if exists "+tab ;
        }

        /**
         * 清除表中数据 <br>
         * 依赖于字段反射，从obj(pojo)重提取属性数据，给予闯将对应ORM 关系映射里的 数据库表 <br>
         * 表名默认为 obj的类名 :obj.getClass()。getSimpleName() <br>
         * 
         * @param obj 待从中提取属性字段数据的javabean
         * @return truncate 的SQL语句
         */
        public static String DDL_TRUNCATE_TABLE(final Object obj) {
            final Class<?> cls = obj instanceof Class<?> ? (Class<?>)obj:obj.getClass();
            return "truncate table "+cls.getSimpleName();
        }

        /**
         * 参数变量的模式
         */
        final static String[] VAR_NAME_PATTERNS = {// 参数变量的模式
            Term.TERM_PATTERN, // unix 变量格式
            "#([a-zA-z0-9]+)" // mybatis 变量格式
        };
        private String name = null;// sql 名称
        private String sqltpl = null;// sql 语句模板， 占位符即模板参数式样：#xxx 字符串类型, ##xxx 数值类型,或是 ${xxx}
        private List<IRecord> sqlctx = null;// sql 上下文{参数集}
    }

    /**
     * 脚本文件:存放着查询语句的模板
     * 
     * @author gbench
     *
     */
    public static class ScriptFile extends SimpleFile{

        /**
         * 创建一个脚本文件对象
         * 
         * @param path 脚本文件路径
         */
        public ScriptFile(final String path) {
            super(path);
            this.initialize();
        }

        /**
         * 创建一个脚本文件路径
         * 
         * @param is 输入流
         */
        public ScriptFile(final InputStream is) {
            super(is);
            this.initialize();
        }

        /**
         * 数据初始化
         */
        public void initialize() {
            final StringBuilder buffer = new StringBuilder();
            final var titlePattern = Pattern.compile(
                "\\s*--\\s*#+\\s*(([^\\s])(.*[^\\s])?)\\s*"); // sql标题开始行
            String title = null;
            for(var line:this.readlines(s->!s.matches("[\\s*]"))){
                var mat = titlePattern.matcher(line);
                if(mat.matches()) {
                    if(title!=null&&buffer.length()>0) {//记录标题
                        stmts.put(title,new SQL(title,buffer.toString()));
                    }//if
                    title = mat.group(1);// 标题
                    buffer.delete(0, buffer.length());//buffer 清空
                }else {
                    if(!line.matches("\\s*--\\s*.*")) {// 去掉注释行
                        if(buffer.length()>0)buffer.append("\n");
                        line=line.replaceAll("\\s*((--)|(//)).*$","");// 去除行尾部的注释  -- 和 --都是注释符号
                        buffer.append(line);
                    }//if
                }//if
            };//for
            stmts.put(title,new SQL(title,buffer.toString()));

            //stmts.forEach((k,v)->{System.out.println("name"+k+"\nstmts\n"+v);});
        }

        /**
         *
         * @param name 语句名称
         * @return SQL 对象
         */
        public SQL get(final String name) {
            return stmts.get(name);
        }

        public Map<String, SQL> getStmts() {
            return stmts;
        }

        private final Map<String, SQL> stmts = new LinkedHashMap<>();// 语句集合

    }
    
    /**
     * Jdbc拦截器:SQL 的处理器
     * 
     * @author xuqinghua
     *
     */
    public static abstract class JdbcPatternPreprocessor {
        /**
         * 构造函数：记得调用初始化函数
         */
        public JdbcPatternPreprocessor() {
            this.initialize();
        }

        /**
         * 初始化函数
         */
        public abstract void initialize();

        /**
         * Pattern/Preprocessor ARGS
         * 
         * @author gbench
         *
         */
        public static class PPARG {

            /**
             * Pattern/Preprocessor ARGS
             * 
             * @param method     方法对象
             * @param params     参数列表
             * @param sqlpattern sql模版
             * @param jdbc       jdbc对象
             */
            public PPARG(final Method method, final IRecord params, final String sqlpattern, final Jdbc jdbc) {
                this.method = method;
                this.params = params;
                this.sqlpattern = sqlpattern;
                this.jdbc = jdbc;
            }

            /**
             * Pattern/Preprocessor ARGS 的名称
             * 
             * @return PPARG 的名称
             */
            public String getName() {
                return method.getName();
            }

            protected Method method;
            protected IRecord params;
            protected String sqlpattern;
            protected Jdbc jdbc;
        }

        /**
         * 函数:PARG -> String
         * 
         * @author gbench
         *
         */
        public interface P2S extends Function<PPARG, String> {
        }

        /**
         * 这是对 SqlPatternPreProcessor的实现
         * 
         * @param method     方法对象
         * @param params     参数列表
         * @param sqlpattern SQL语句
         * @param jdbc       jdbc对象
         * @return sqlpattern 实例化的SQL语句
         */
        public String handle(final Method method, final IRecord params, final String sqlpattern, final Jdbc jdbc) {
            final var parg = new PPARG(method, params, sqlpattern, jdbc);// 把接口参数package成统一参数对象．
            final String key = parg.getName();
            if (!callbacks.has(key)) return sqlpattern;
            return callbacks.evaluate(key, parg, String.class);
        }

        /**
         * 在接口函数中实例化：按照如下实现，就可以 <br>
         * Jdbc.newInstance(xxxDatabase.class,new JdbcPatternPreprocessor(){ <br>
         * }::handle); <br>
         * callbacks=REC("methodName",(PPARG)pp->{return pparg.pattern}); <br>
         */
        protected IRecord callbacks;
    }

    /**
     * JDBC访问数据库
     * @author gbench
     *
     */
    public static class Jdbc {

        /**
         * 创建jdbc连接对象
         * 
         * @param supplierConn 链接贩卖商，也就是不适用传统的DriverManager,而是第三方来提供。
         */
        public Jdbc(Supplier<Connection> supplierConn) {
            this.supplierConn = supplierConn;// 初始化连接贩卖商
        }

        /**
         * 创建jdbc连接对象
         * @param ds 数据源
         */
        public Jdbc(DataSource ds){
            this.supplierConn=()->{
                Connection conn =null;
                try {conn = ds.getConnection();}catch(Exception e) {e.printStackTrace();}
                return conn;
            };// 初始化连接贩卖商
        }

        /**
         * 创建jdbc连接对象
         * 
         * @param driver 驱动程序
         * @param url 连接url
         * @param user 数据库用户
         * @param password 数据库密码
         */
        public Jdbc(String driver,String url,String user,String password){
            this.init(driver, url, user, password);
        }
        
        /**
         * 创建jdbc连接对象
         * 
         * @param rec: 需要包含key:driver,url, user, password
         */
        public Jdbc(IRecord rec) {
            var props = rec.toProps();
            this.init(props.getProperty("driver"), props.getProperty("url"), 
                props.getProperty("user"), props.getProperty("password"));
        }
        
        /**
         * 创建jdbc连接对象
         * 
         * @param map: 需要包含key:driver,url, user, password
         */
        public Jdbc(Map<?,?> map) {
            var props = REC(map).toProps();
            this.init(props.getProperty("driver"), props.getProperty("url"), 
                props.getProperty("user"), props.getProperty("password"));
        }
        
        /**
         * 创建jdbc连接对象
         * 
         * @param props: 需要包含key:driver,url, user, password
         */
        public Jdbc(Properties props) {
            this.init(props.getProperty("driver"), props.getProperty("url"), 
                props.getProperty("user"), props.getProperty("password"));
        }
        
        /**
         * Jdbc上下文:提供一个JDBC的基本操作参数 <br>
         * 注意serverTimezone一定需要加入：否则结果返回的时间会有问题：MYSQL采用格林乔治时间．<br>
         * driver 驱动程序：默认 "com.mysql.cj.jdbc.Driver"; <br>
         * url:数据据连接字符串，默认 "jdbc:mysql://localhost:3306/hello?serverTimezone=GMT%2B8";
         * <br>
         * user：用户名，默认 "root" <br>
         * password：密码，默认 "123456" <br>
         * 
         * @author gbench
         *
         */
        @Target(value = { ElementType.TYPE, ElementType.METHOD })
        @Retention(value = RetentionPolicy.RUNTIME)
        public @interface JdbcConfig {
            String driver() default "com.mysql.cj.jdbc.Driver";

            String url() default "jdbc:mysql://localhost:3306/hello?serverTimezone=GMT%2B8";

            String user() default "root";

            String password() default "123456";
        }
        
        /**
         * 执行一个jdbc语句<br>
         * value 中提供的是一个 sql 语句模板：比如 ："select * from t_user where id={0}" <br>
         * 语句模板采用 MessageFormat 给予格式化处理，占位符用 {index},形式给予提供， <br>
         * index从0开始，代表装饰函数的第一个参数，第二个参数，以此类推 <br>
         * 修饰的模仿默认返回未 List<IRecord> <br>
         * 也可是一个用户自定义的 POJO 此时会采用 IRecord.OBJINIT 来吧IRecord转换成 POJO. <br>
         * 对于是接口中的default 方法，如果该方法的最后一个参数为空数值，则会把SQL语句的返回数值传入到该该参数中，并调用该默认方法． <br>
         * 
         * @author gbench
         *
         */
        @Target(value = { ElementType.METHOD })
        @Retention(value = RetentionPolicy.RUNTIME)
        public @interface JdbcQuery {
            String value() default "";
        }
        
        /**
         * 使用preparedStatement 模板 <br>
         * 执行一个jdbc语句，value 中提供的是一个 sql 语句模板：比如 ："select * from t_user where id=?" <br>
         * ? 占位符将由参数顺序给予依次替换． <br>
         * 也可是一个用户自定义的 POJO 此时会采用 IRecord.OBJINIT 来吧IRecord转换成 POJO. <br>
         * 对于是接口中的default 方法，如果该方法的最后一个参数为空数值，则会把SQL语句的返回数值传入到该该参数中，并调用该默认方法． <br>
         * 
         * @author gbench
         *
         */
        @Target(value = { ElementType.METHOD })
        @Retention(value = RetentionPolicy.RUNTIME)
        public @interface JdbcPreparedQuery {
            String value() default "";
        }
        
        /**
         * 这是一个事务级别的SQL语句执行级别． 执行一个jdbc语句，value 中提供的是一个 sql 语句模板：比如 ： "update t_user set
         * name=''{1}'' where id={0}" 语句模板采用 MessageFormat 给予格式化处理，占位符用
         * {index},形式给予提供，index从0开始，<br>
         * 代表装饰函数的第一个参数，第二个参数，以此类推
         * 
         * @author gbench
         *
         */
        @Target(value = { ElementType.METHOD })
        @Retention(value = RetentionPolicy.RUNTIME)
        public @interface JdbcExecute {
            String[] value() default {};// sql语句集合．
        }
        
        /**
         * 这是一个事务级别的SQL语句执行级别． 执行一个jdbc语句，value 中提供的是一个 sql 语句模板：比如 ： "update t_user set
         * name=''{1}'' where id={0}" 语句模板采用 MessageFormat 给予格式化处理，占位符用
         * {index},形式给予提供，index从0开始，<br>
         * 代表装饰函数的第一个参数，第二个参数，以此类推
         * 
         * @author gbench
         *
         */
        @Target(value = { ElementType.METHOD })
        @Retention(value = RetentionPolicy.RUNTIME)
        public @interface JdbcPreparedExecute {
            String[] value() default {};// sql语句集合．
        }
        
        /**
         * 带有连接的数据查询
         * 
         * @param conn  数据库连接
         * @param query 查询语句
         * @return 查询结果
         * @throws SQLException
         */
        public static List<IRecord> queryWithConnection(final Connection conn, final String query) throws SQLException {
            final var pstmt = conn.prepareStatement(query);// 生成SQL语句
            return preparedQuery(() -> pstmt, null);
        }

        /**
         * 带有连接的数据查询
         * 
         * @param conn    数据库连接
         * @param query   查询语句
         * @param prepare PreparedStatement 的查询前的数据处理。比如设置 PreparedStatement 的各个参数。
         * @return 查询结果
         * @throws SQLException
         */
        public static List<IRecord> queryWithConnection(final Connection conn, final String query,
                final Consumer<PreparedStatement> prepare) throws SQLException {
            final var pstmt = conn.prepareStatement(query);// 生成SQL语句
            return preparedQuery(() -> pstmt, prepare);
        }

        /**
         * preparedStatement 结果处理。
         * 
         * @param pstmt parepared statement 生成器
         * @return 查询的结果集合
         * @throws SQLException
         */
        public static List<IRecord> preparedQuery(final Supplier<PreparedStatement> pstmt) throws SQLException {
            return preparedQuery(pstmt, (Consumer<PreparedStatement>) null);
        }

        /**
         * preparedStatement 结果处理。
         * 
         * @param pstmt   parepared statement 生成器
         * @param prepare parepared statement的参数准备
         * @return 查询的结果集合
         * @throws SQLException
         */
        public static List<IRecord> preparedQuery(final Supplier<PreparedStatement> pstmt,
                final Consumer<PreparedStatement> prepare) throws SQLException {

            final List<IRecord> ll = new LinkedList<>();
            try (final var stmt = pstmt.get()) {
                if (prepare != null) prepare.accept(stmt);
                try (final var rs = stmt.executeQuery()) {
                    while (rs.next()) ll.add(readline(rs));
                } // try rs
            } // try stmt

            return ll;
        }

        /**
         * 执行prepared statment
         * 
         * @param conn 数据库连接
         * @return 查询的结果集合
         * @throws SQLException
         */
        public static void executeWithConnection(final Connection conn, final String sql) throws SQLException {
            executeWithConnection(conn, sql, (Consumer<PreparedStatement>) null);
        }
        
        /**
         * 执行prepared statment
         * 
         * @param conn 数据库连接
         * @param sql  prepare sql语句的处理
         * @return 查询的结果集合
         * @throws SQLException
         */
        public static void executeWithConnection(final Connection conn, String sql, Consumer<PreparedStatement> prepare)
                throws SQLException {
            final var pstmt = conn.prepareStatement(sql);
            preparedExecute(() -> pstmt, prepare);
        }

        /**
         * 执行prepared statment
         * 
         * @param pstmt parepared statement 生成器
         * @return 无
         * @throws SQLException
         */
        public static void preparedExecute(final Supplier<PreparedStatement> pstmt) throws SQLException {
            preparedExecute(pstmt, (Consumer<PreparedStatement>) null,
                    (BiFunction<Boolean, PreparedStatement, ?>) null);
        }

        /**
         * 执行prepared statment
         * 
         * @param pstmt   parepared statement 生成器
         * @param prepare parepared statement的参数准备
         * @return 无
         * @throws SQLException
         */
        public static void preparedExecute(Supplier<PreparedStatement> pstmt, Consumer<PreparedStatement> prepare)
                throws SQLException {
            preparedExecute(pstmt, prepare, (BiFunction<Boolean, PreparedStatement, ?>) null);
        }

        /**
         * 执行prepared statment
         * 
         * @param pstmt    parepared statement 生成器
         * @param callback 返回结果的处理
         * @return callback 处理的结果
         * @throws SQLException
         */
        public static <T> T preparedExecute(Supplier<PreparedStatement> pstmt,
                BiFunction<Boolean, PreparedStatement, T> callback) throws SQLException {
            return preparedExecute(pstmt, (Consumer<PreparedStatement>) null, callback);
        }
        
        /**
         * 执行prepared statment
         * 
         * @param pstmt    parepared statement 生成器
         * @param prepare  parepared statement的参数准备
         * @param callback 返回结果的处理
         * @return callback 处理的结果
         * @throws SQLException
         */
        public static <T> T preparedExecute(final Supplier<PreparedStatement> pstmt,
                final Consumer<PreparedStatement> prepare, BiFunction<Boolean, PreparedStatement, T> callback)
                throws SQLException {

            T t = null;// 返回结果
            try (var stmt = pstmt.get()) {
                if (prepare != null)
                    prepare.accept(stmt);
                if (callback != null)
                    t = callback.apply(stmt.execute(), stmt);
            } // try stmt

            return t;// 返回结果
        }
        
        /**
         * 从ResultSet 当前游标位置 中读取一条数据。<br>
         * 不对结果集合ResultSet做任何改变,游标位置需要事先设置好<br>
         * 即不会移动ResultSet的cursor。所以读取第一条数据的时候需要在外部进行rs.next()<br>
         * Record 的key 采用rs.getMetaData().getColumnLabel(索引）来获取。<br>
         * 
         * @param rs 结果集合
         * @return 结果集数据的record的表示,出现异常则返回null
         */
        public static IRecord readline(final ResultSet rs) {
            final var rec = REC();
            try{
                return Jdbc.readline(rs,Jdbc.labels2(rs));
            }catch(Exception e) {
                return rec;
            }
        }
        
        /**
         * 从ResultSet 当前游标位置 中读取一条数据。<br>
         * 不对结果集合ResultSet做任何改变,游标位置需要事先设置好<br>
         * 即不会移动ResultSet的cursor。所以第一条数据的时候需要在外部进行rs.next()<br>
         * Record 的key 采用rs.getMetaData().getColumnLabel(索引）来获取。<br>
         * 
         * @param rs 结果集合
         * @param lbls 键名集合
         * @return 结果集数据的record的表示,出现异常则返回null
         */
        public static IRecord readline(final ResultSet rs,final String [] lbls) {
            IRecord rec = null;// 默认的非法结果
            try {
                rec = REC();
                final var n = lbls.length;
                for (int i = 0; i < n; i++) {// 读取当前行的各个字段信息。
                    final var name = lbls[i]; // 提取键名
                    final var value = rs.getObject(i + 1); // 提取键值
                    rec.add(name, value);
                } // for
            } catch (Exception e) {
                e.printStackTrace();
            } // try

            return rec;
        }
        
        /**
         * 从当前游标开始（包含)依次向后读取数据<br>
         * 若当前游标位于第一行以前则先移动游标到第一行而后读取 <br>
         * Record 的key 采用rs.getMetaData().getColumnLabel(索引）来获取。<br>
         * 
         * @param rs    结果集合
         * @param close 读完是否关闭rs,true 表示读完后关闭rs
         * @return 结果集数据的records 集合
         * @throws SQLException
         */
        public static List<IRecord> readlines(final ResultSet rs, boolean close) throws SQLException {
            final var recs = new LinkedList<IRecord>();
            final var lbls = Jdbc.labels2(rs);
            try { // 保护没有实现isBeforeFirst系列的驱动程序可以正确运行
                if (!rs.isBeforeFirst()) recs.add(readline(rs, lbls)); // 记录当前节点数据
                if (rs.isAfterLast()) return recs;
            } catch (Exception e) {
                // e.printStackTrace();
            }
            while (rs.next()) recs.add(readline(rs, lbls));
            if (close) rs.close();
            return recs;
        }
        
        /**
         * 从当前游标（包含)开始依次向后读取数据<br>
         * 若当前游标位于第一行以前则先移动游标到第一行而后读取 <br>
         * Record 的key 采用rs.getMetaData().getColumnLabel(索引）来获取。<br>
         * 
         * @param rs    结果集合
         * @return 结果集数据的record的流
         * @throws SQLException
         */
        public static Stream<IRecord> readlineS(final ResultSet rs) throws SQLException {
            return Jdbc.readlineS(rs, false);
        }
        
        /**
         * 从当前游标开始（包含)依次向后读取数据<br>
         * 若当前游标位于第一行以前则先移动游标到第一行而后读取 <br>
         * Record 的key 采用rs.getMetaData().getColumnLabel(索引）来获取。<br>
         * 
         * @param rs    结果集合
         * @param close 读完是否关闭rs,true 表示读完后关闭rs,<br>
         *              注意关闭事件的触发是根据 是否读到rs结果集合的末尾,<br>
         *              即仅当 当读取数据末端 并且 明确指了close标记的时候才给与关闭结果集合，其他情形则不给与关闭
         * @return 结果集数据的record的流
         * @throws SQLException
         */
        public static Stream<IRecord> readlineS(final ResultSet rs, boolean close) throws SQLException {
            final var lbls = Jdbc.labels2(rs);
            try {// 保护没有实现isBeforeFirst系列的驱动程序可以正确运行
                if (rs.isBeforeFirst()) rs.next(); // 初始位置
                if (rs.isAfterLast()) return Stream.of();
            } catch (Exception e) {
                // e.printStackTrace();
            } // try
            
            final var stream = Stream.iterate(readline(rs, lbls), p -> {
                return LittleTree.trycatch((ResultSet r) -> {
                    final var b = rs.isLast();// 当前指针是否位于最后一条记录
                    if (!b) {// 不是最后一条数据,先移动然后读取
                        rs.next();
                        return readline(rs, lbls);
                    } else {// 已经读取到了最后一条数据,返回null
                        if (close)
                            LittleTree.trycatch3(ResultSet::close).accept(rs);
                        return null;
                    }
                }).apply(rs);
            }).takeWhile(Objects::nonNull);
            return stream;
        }
        
        /**
         * 对 lbls 带有内容调整的行数据读取 <br>
         * 从ResultSet 中读取一条数据。<br>
         * 不对结果集合ResultSet做任何改变,所以需要自动调整rs的游标位置<br>
         * 即不会移动ResultSet的cursor。所以第一条数据的时候需要在外部进行rs.next()<br>
         * Record 的key 采用rs.getMetaData().getColumnLabel(索引）来获取。<br>
         * 
         * @param rs   结果集合
         * @param lbls 键名集合
         * @return 结果集数据的record的表示,出现异常则返回null
         */
        public static IRecord readline2(final ResultSet rs, final String[] lbls) {
            try {
                final var n = rs.getMetaData().getColumnCount();
                return Jdbc.readline(rs, Jdbc.adjustLabels(n, lbls));
            } catch (Exception e) {
                return REC();
            }
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。 <br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。<br>
         * 
         * @param <T> 访问接口 类的类型
         * @param itf 访问接口
         * @return 数据库访问的代理对象
         */
        public static <T> T newInstance(final Class<T> itf) {
            
            return newInstance(itf,(SqlPatternPreprocessor)null);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 
         * @param <T>                     访问接口 类的类型
         * @param itf                     访问接口
         * @param sqlpattern_preprocessor sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．<br>
         *                                是一个(m,a,p,j)->p 的形式<br>
         *                                method(m) 方法对象,<br>
         *                                params(a args) 参数列表:name->value,<br>
         *                                sqlpattern(p pattern) sql模板 ，sql
         *                                模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *                                jdbc(j) 当前连接的数据库对象．<br>
         * @return 书苦苦访问的代理对象
         */
        public static <T> T newInstance(final Class<T> itf, final SqlPatternPreprocessor sqlpattern_preprocessor) {
            
            return newInstance(itf,(Map<String,String>)null,sqlpattern_preprocessor);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 
         * @param <T>                     访问接口 类的类型
         * @param itf                     访问接口
         * @param sqlpattern_preprocessor sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．<br>
         *                                是一个(m,a,p,j)->p 的形式 <br>
         *                                method(m) 方法对象, <br>
         *                                params(a args) 参数列表:name->value, <br>
         *                                sqlpattern(p pattern) sql模板 ，sql
         *                                模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *                                jdbc(j) 当前连接的数据库对象．<br>
         * @param jdbc_postprocessor      事后处理
         * @return 书苦苦访问的代理对象
         */
        public static <T> T newInstance(final Class<T> itf, final SqlPatternPreprocessor sqlpattern_preprocessor,
                final JdbcPostProcessor<?> jdbc_postprocessor) {
            
            return newInstance(itf,(Map<?,?>)null,sqlpattern_preprocessor,jdbc_postprocessor);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 请确保jdbcConfig 含有有效的driver,url,user,password <br>
         * 也可以直接加入一个 jdbcClass键 jdbcConfig.add("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个Map<?,?>的构造函数<br>
         * jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * 或者是直接传入一个非空的Jdbc实例。jdbcConfig.add("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * 
         * @param <T>        访问接口 类的类型
         * @param itf        访问接口
         * @param jdbcConfig jdbc的配置：driver,url,user,password<r> 也可以直接加入一个 jdbcClass键
         *                   jdbcConfig.add("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *                   jdbcClass键还可以直接是一个类对象：<br>
         *                   jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个Map<?,?>的构造函数 <br>
         *                   或者是直接传入一个非空的Jdbc实例。jdbcConfig.add("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，<br>
         *                   选取第一个。<br>
         * @return 数据库访问的代理对象
         */
        public static <T> T newInstance(final Class<T> itf, final IRecord jdbcConfig) {
            
            return newInstance(itf,jdbcConfig,(SqlPatternPreprocessor)null);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 请确保jdbcConfig 含有有效的driver,url,user,password <br>
         * 也可以直接加入一个 jdbcClass键 jdbcConfig.add("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数<br>
         * jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * 或者是直接传入一个非空的Jdbc实例。jdbcConfig.add("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * 
         * @param <T> 访问接口 类的类型
         * @param itf 访问接口
         * @param jdbcConfig jdbc的配置：driver,url,user,password<r>
         *      也可以直接加入一个 jdbcClass键 jdbcConfig.add("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      或者是直接传入一个非空的Jdbc实例。jdbcConfig.add("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         *
         * @param sqlpattern_preprocessor  sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表． <br>
         * 是一个(m,a,p,j)->p 的形式 <br>
         * method(m) 方法对象, <br>
         * params(a args) 参数列表:name->value, <br>
         * sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力, <br>
         * jdbc(j) 当前连接的数据库对象．<br>
         * @return 书苦苦访问的代理对象
         */
        public static <T> T newInstance(final Class<T> itf,final IRecord jdbcConfig, final SqlPatternPreprocessor sqlpattern_preprocessor) {
            
            return newInstance(itf,jdbcConfig.toMap(),sqlpattern_preprocessor);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 请确保jdbcConfig 含有有效的driver,url,user,password <br>
         * 也可以直接加入一个 jdbcClass键 jdbcConfig.add("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数<br>
         * jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * 或者是直接传入一个非空的Jdbc实例。jdbcConfig.add("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * 
         * @param <T> 访问接口 类的类型
         * @param itf 访问接口
         * @param jdbcConfig jdbc的配置：driver,url,user,password<r>
         *      也可以直接加入一个 jdbcClass键 jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * @return 数据库访问的代理接口
         */
        public static <T> T newInstance(final Class<T> itf,final Map<?,?> jdbcConfig) {
            
            return newInstance(itf,jdbcConfig,(SqlPatternPreprocessor)null);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 请确保jdbcConfig 含有有效的driver,url,user,password <br>
         * 也可以直接加入一个 jdbcClass键 jdbcConfig.add("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数<br>
         * jdbcClass键还可以直接是一个类对象： jdbcConfig.add("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * 或者是直接传入一个非空的Jdbc实例。jdbcConfig.add("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * 
         * @param <T> 访问接口 类的类型
         * @param itf 访问接口
         * @param jdbcConfig jdbc的配置：driver,url,user,password<r>
         *      也可以直接加入一个 jdbcClass键 jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * @param sqlpattern_preprocessor sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．
         * 是一个(m,a,p,j)->p 的形式 <br>
         * method(m) 方法对象, <br>
         * params(a args) 参数列表:name->value, <br>
         * sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力, <br>
         * jdbc(j) 当前连接的数据库对象．<br>
         * @return 数据库访问的代理接口
         */
        public static <T> T newInstance(final Class<T> itf,final Map<?,?> jdbcConfig,
            final SqlPatternPreprocessor sqlpattern_preprocessor) {
            
            return newInstance(itf,jdbcConfig,sqlpattern_preprocessor,
                (SqlInterceptor<List<IRecord>>)null);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 请确保jdbcConfig 含有有效的driver,url,user,password <br>
         * 也可以直接加入一个 jdbcClass键 jdbcConfig.add("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数<br>
         * jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * 或者是直接传入一个非空的Jdbc实例。jdbcConfig.add("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * 
         * @param <T> 访问接口 类的类型
         * @param itf 访问接口
         * @param interceptor SqlInterceptor<List<IRecord>>:方法执行的接获函数,返回一个 List<IRecord>,如果非空，表示完成接获<br>
         * 代理对象的执行结果就是该interceptor所接获的结果，反之就是 就会继续执行。后续的操作。<br>
         * 是一个(m,a,p,j)->p 的形式<br>
         * method(m) 方法对象,<br>
         * params(a args) 参数列表:name->value,<br>
         * sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         * jdbc(j) 当前连接的数据库对象．<br>
         * @return 数据库访问的代理接口
         */
        public static <T> T newInstance(final Class<T> itf, final SqlInterceptor<List<IRecord>> interceptor) {
            
            return newInstance(itf,(Map<String,String>)null,(SqlPatternPreprocessor)null,
                (SqlInterceptor<List<IRecord>>)interceptor);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 请确保jdbcConfig 含有有效的driver,url,user,password <br>
         * 也可以直接加入一个 jdbcClass键 jdbcConfig.add("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数<br>
         * jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * 或者是直接传入一个非空的Jdbc实例。jdbcConfig.add("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * 
         * @param <T> 访问接口 类的类型
         * @param itf 访问接口
         * @param jdbcConfig jdbc的配置：driver,url,user,password<r>
         *      也可以直接加入一个 jdbcClass键 jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         *
         * @param interceptor SqlInterceptor<List<IRecord>>:方法执行的接获函数,返回一个 List<IRecord>,如果非空，表示完成接获
         * 代理对象的执行结果就是该interceptor所接获的结果，反之就是 就会继续执行。后续的操作。<br>
         * 是一个(m,a,p,j)->p 的形式<br>
         * method(m) 方法对象,<br>
         * params(a args) 参数列表:name->value,<br>
         * sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         * jdbc(j) 当前连接的数据库对象．<br>
         * @return 数据库访问的代理接口
         */
        public static <T> T newInstance(final Class<T> itf,final IRecord jdbcConfig,
            final SqlInterceptor<List<IRecord>> interceptor) {
            
            final Map<?,?> cfg = jdbcConfig == null?null:jdbcConfig.toMap();
            return newInstance(itf,cfg,(SqlPatternPreprocessor)null,
                (SqlInterceptor<List<IRecord>>)interceptor);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。<br> 
         * 请确保jdbcConfig 含有有效的driver,url,user,password <br>
         * 也可以直接加入一个 jdbcClass键 jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数<br>
         * jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * 或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * 
         * @param <T> 访问接口 类的类型
         * @param itf 访问接口
         * @param jdbcConfig jdbc的配置：driver,url,user,password<r>
         *      也可以直接加入一个 jdbcClass键 jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         *
         * @param interceptor SqlInterceptor<List<IRecord>>:方法执行的接获函数,返回一个 List<IRecord>,如果非空，表示完成接获<br>
         * 代理对象的执行结果就是该interceptor所接获的结果，反之就是 就会继续执行。后续的操作。<br>
         * 是一个(m,a,p,j)->p 的形式<br>
         * method(m) 方法对象,<br>
         * params(a args) 参数列表:name->value,<br>
         * sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         * jdbc(j) 当前连接的数据库对象．<br>
         * @return 数据库访问的代理接口
         */
        public static <T> T newInstance(final Class<T> itf,final Map<?,?> jdbcConfig,
            final SqlInterceptor<List<IRecord>> interceptor) {
            
            return newInstance(itf,jdbcConfig,(SqlPatternPreprocessor)null,
                (SqlInterceptor<List<IRecord>>)interceptor);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 请确保jdbcConfig 含有有效的driver,url,user,password<br>
         * 也可以直接加入一个 jdbcClass键 jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数
         * jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * 或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。
         * 
         * @param <T> 访问接口 类的类型
         * @param itf 访问接口
         * @param jdbcConfig jdbc的配置：driver,url,user,password<r>
         *     也可以直接加入一个 jdbcClass键 jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *     jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *     或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         *
         * @param sqlpattern_preprocessor sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．
         * 是一个(m,a,p,j)->p 的形式<br>
         * method(m) 方法对象,<br>
         * params(a args) 参数列表:name->value,<br>
         * sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         * jdbc(j) 当前连接的数据库对象．<br>
         * @param jdbc_postprocessor 结果的后置处理处理器：对一般标准的处理结果进行后续处理。
         * @return 数据库访问的代理接口
         */
        public static <T,U> T newInstance(final Class<T> itf,final Map<?,?> jdbcConfig,
            final SqlPatternPreprocessor sqlpattern_preprocessor,
            final JdbcPostProcessor<U> jdbc_postprocessor) {
            
            return newInstance(itf,jdbcConfig,sqlpattern_preprocessor,
                (SqlInterceptor<List<IRecord>>)null,jdbc_postprocessor);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。 <br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 请确保jdbcConfig 含有有效的driver,url,user,password <br>
         * 也可以直接加入一个 jdbcClass键 jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数
         * jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * 或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。
         * 
         * @param <T> 访问接口 类的类型
         * @param<U> JdbcPostProcessor 的返回结果类型：这是一个类型占位符
         * @param itf 访问接口 <br>
         * @param jdbcConfig jdbc的配置：driver,url,user,password<r>
         *     也可以直接加入一个 jdbcClass键 jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *     jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *     或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * 
         * @param sqlpattern_preprocessor sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．<br>
         * 是一个(m,a,p,j)->p 的形式 <br>
         * method(m) 方法对象,<br>
         * params(a args) 参数列表:name->value,<br>
         * sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         * jdbc(j) 当前连接的数据库对象．
         * 
         * @param sqlinterceptor SQL方法执行拦截器：需要注意 sqlinterceptor 是在 sqlpattern_preprocessor 处理之后才给予调用的。<br>
         *    也就是说先调用sqlpattern_preprocessor，然后在调用sqlinterceptor;<br>
         *    method(m) 方法对象,<br>
         *    params(a args) 参数列表:name->value,<br>
         *    sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *    jdbc(j) 当前连接的数据库对象．
         * @return 数据库访问的代理接口
         */
        public static <T,U> T newInstance(final Class<T> itf,
            final Map<?,?> jdbcConfig, final SqlPatternPreprocessor sqlpattern_preprocessor,
            final SqlInterceptor<List<IRecord>> sqlinterceptor) {
            
            return newInstance(itf,jdbcConfig,sqlpattern_preprocessor,
                sqlinterceptor,(JdbcPostProcessor<U>)null);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 <br>
         * 请确保jdbcConfig 含有有效的driver,url,user,password<br>
         * 也可以直接加入一个 jdbcClass键 jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         * 或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * 
         * @param <T> 访问接口 类的类型
         * @param <U> jdbcPostProcessor的返回结果的类型
         * @param itf 访问接口
         * @param jdbcConfig jdbc的配置：driver,url,user,password<r>
         *      也可以直接加入一个 jdbcClass键： jdbcConfig.put("jdbcClass",MyJdbc.class.getName()),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      jdbcClass键还可以直接是一个类对象： jdbcConfig.put("jdbcClass",MyJdbc.class),jdbcClass 需要有一个 Map<?,?>的构造函数 <br>
         *      或者是直接传入一个非空的Jdbc实例。jdbcConfig.put("_",new MyJdbc),键名可以任意，当存在多个Jdbc实例的时候，选取第一个。<br>
         * 
         * @param sqlpattern_preprocessor sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．
         * 是一个(m,a,p,j)->p 的形式<br>
         * method(m) 方法对象,<br>
         * params(a args) 参数列表:name->value,<br>
         * sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         * jdbc(j) 当前连接的数据库对象．<br>
         * 
         * @param sqlinterceptor SQL方法执行拦截器：需要注意 sqlinterceptor 是在 sqlpattern_preprocessor 处理之后才给予调用的。<br>
         *    也就是说先调用sqlpattern_preprocessor，然后在调用sqlinterceptor;<br>
         *    method(m) 方法对象,<br>
         *    params(a args) 参数列表:name->value,<br>
         *    sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *    jdbc(j) 当前连接的数据库对象．<br>
         * @param jdbcPostProcessor 结果的后置处理处理器：对一般标准的处理结果进行后续处理。<br>
         * @return 数据库访问的代理接口
         */
        public static <T,U> T newInstance( final Class<T> itf, final Map<?,?> jdbcConfig,
            final SqlPatternPreprocessor sqlpattern_preprocessor,
            final SqlInterceptor<List<IRecord>> sqlinterceptor,
            final JdbcPostProcessor<U> jdbcPostProcessor ) {
            
            final var jc = itf.getAnnotation(JdbcConfig.class);// 获取jdbc的配置
            final var jcfg = REC( null==jdbcConfig?new HashMap<String,String>():jdbcConfig);// 提供默认数据库配置
            T objT = null;// 接口实例对象
            try {
                Jdbc _jdbc = jcfg.findOne(Jdbc.class);// 尝试直接在配置类中获取Jdbc对象,如果存在jdbc对象，则直接使用。
                if(_jdbc==null && jdbcConfig!=null ) {
                    try {
                        final var jdbcClass = jdbcConfig.get("jdbcClass");// 提取jdbc Class
                        if(jdbcClass!=null) {
                            @SuppressWarnings("unchecked")
                            final Class<Jdbc> jdbcClazz = jdbcClass instanceof Class<?>
                                ? (Class<Jdbc>) jdbcClass // 直接转换成Jdbc 类对象 
                                : (Class<Jdbc>) Class.forName(jdbcClass.toString()); // 通过类名加载类对象。
                            if(jdbcClazz!=null) { // jdbcClazz 可非空判断
                                final var ctor = jdbcClazz.getConstructor(Map.class);
                                ctor.setAccessible(true);
                                if(ctor!=null) _jdbc = ctor.newInstance(jdbcConfig);
                            }//if jdbcClazz 可非空判断
                        }//if
                    }catch(Exception ex) {
                        ex.printStackTrace();
                    }
                }// _jdbc 对象
                
                final var jdbc = _jdbc!=null // _jdbc 的构造优先。
                    ? _jdbc 
                    :   ( jdbcConfig==null || jdbcConfig.size()<1 ) && ( jc == null ) 
                        ? null // 没有默认配置
                        : new Jdbc(// 使用Jdbc创建对象
                            jcfg.computeIfAbsent("driver",k->jc==null?null:jc.driver()),
                            jcfg.computeIfAbsent("url",k->jc==null?null:jc.url()),
                            jcfg.computeIfAbsent("user",k->jc==null?null:jc.user()),
                            jcfg.computeIfAbsent("password",k->jc==null?null:jc.password())
                        ); // new Jdbc 船舰jdbc对象

                if(jdbc==null) {
                    System.err.println(MFT("尚未配置Jdbc实例,无法处理 数据库连接操作,因为jdbc的配置:\njdbc:{0},\n@JdbcConfig:{1}！",jdbcConfig,jc));
                }//if jdbc==null

                objT =  newInstance(itf,jdbc,sqlpattern_preprocessor,sqlinterceptor,jdbcPostProcessor);
            }catch(Exception e) {
                e.printStackTrace();
            }
            
            return objT;// 返回接口实例
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。 <br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。
         * 
         * @param <T>  访问接口 类的类型
         * @param itf  访问接口
         * @param jdbc 数据库访问接口
         * @return 数据库访问的代理接口
         */
        public static synchronized <T> T newInstance(final Class<T> itf,final Jdbc jdbc) {
            
            return newInstance(itf,jdbc,null,null);
        }
        
        /**
         * SQL 语句模板的预处理器 <br>
         * 函数接口 String handle(Method method,IRecord params,String sqlpattern,Jdbc jdbc)
         * 对 <br>
         * 请求的 sqlpattern 进行预处理。比如读写分离，分库分表的处理等。 <br>
         * -- method 方法对象, <br>
         * -- params 参数列表:name->value, <br>
         * -- sqlpattern sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力, <br>
         * -- jdbc 当前连接的数据库对象． <br>
         * 
         * @author xuqinghua
         *
         */
        @FunctionalInterface
        public interface SqlPatternPreprocessor {
            /**
             * sql 模板的参数的预处理函数。 <br>
             * 比如可以有这样一种预处理的实现SQL变换的预处理实现，当然也可以采用 另外的自定义实现 等。 <br>
             * 可以有某个SqlPatternPreprocessor 的实现自动对读sqlpattern中的命名参数进行替换： <br>
             * method:public User getUserByName(String name); <br>
             * sqlpattern: select * from user where name=#name <br>
             * params:REC("name","张三") <br>
             * 返回值:select * from user where name="张三" <br>
             * 
             * 需要注意对于sql语句模板不能以#开头。
             * 
             * @param method     方法对象
             * @param params     形参与实参之间的对应关系列表:{name/形式参数的名称->value/实际参数的数值}
             * @param sqlpattern sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力．
             * @param jdbc       当前连接的数据库对象．
             * @return 处理后的sql模板
             */
            String handle(final Method method, final IRecord params, final String sqlpattern, final Jdbc jdbc);

            /**
             * SqlPatternPreprocessor 的名称
             * 
             * @return SqlPatternPreprocessor 的名称,默认名称为 none,表示没有名称
             */
            default String name() {
                return "none";
            }
            
            /**
             * SqlPatternPreprocessor 的执行状态数据
             * 
             * @return SqlPatternPreprocessor 的执行状态数据
             */
            default IRecord status() {
                return null;
            }
        }
        
        /**
         * 命名SQL文件（namedsql file）是一个  sql 脚本文件 只是 这个 sql脚本 包含有特别的 用于说明 语句结构的 文法注释。<br>
         * 一个 namedsql file 是如下的结构： <br>
         * 其中 语句名称用 # 空格  ‘语句名称’ 的形式。 而不带#与 名称之间不带有空格的 将被视作一般注释。给予忽略。<br>
         * 即他会按照如下进行解释：<br>
         * <br>
         * 命名SQL文件的解析，类似于如下的格式。需要注意的#后面必须带有空格，才可以作为 sql语句的名称<br>
         * 需要注意：‘# count1’  才是sql语句的名称，而‘#name:  用户名称’ 则是参数的说明。区别在于<br> 
         * count1与# 之间有一个 空格。而name 与#之间没有 <br>
         * 
         * -- -------------------------- <br>
         * -- # count1 <br>
         * -- name:  用户名称 <br>
         * -- --------------------------<br>
         * select count(*) from t_user <br>
         * where name = #name <br>
         *
         * -- --------------------------<br>
         * -- # count2
         * -- --------------------------<br>
         * select count(*) from t_user;<br>
         *
         * -- --------------------------<br>
         * -- # insertUser <br>
         * -- -------------------------- <br>
         * insert into ##tableName (name,password,sex,address,birth,phonenumber,email) <br>
         * values (#name,#password,#sex,#address,#birth,#phonenumber,#email) <br>
         * 
         * @param lines 行文本序列
         * @return 命名sql 集合。
         */
        public static Map<String,String> parse2namedsqls(final Stream<String>lines){
            
            return parse2namedsqls(lines,true);
        }
        
        /**
         * 命名SQL文件的解析，类似于如下的格式。需要注意的#后面必须带有空格，才可以作为 sql语句的名称 <br>
         * 需要注意：‘# count1’  才是sql语句的名称，而‘#name:  用户名称’ 则是参数的说明。区别在于  <br>
         * count1与# 之间有一个 空格。而name 与#之间没有 <br>
         * 
         * -- -------------------------- <br>
         * -- # count1 <br>
         * -- #name: 用户名称 <br>
         * -- -------------------------- <br>
         * select count(*) from t_user <br>
         * where name = #name <br>
         *
         * -- -------------------------- <br>
         * -- # count2 <br>
         * -- -------------------------- br>
         * select count(*) from t_user; <br>
         *
         * -- -------------------------- <br>
         * -- # insertUser <br>
         * -- -------------------------- <br>
         * insert into ##tableName (name,password,sex,address,birth,phonenumber,email) <br>
         * values (#name,#password,#sex,#address,#birth,#phonenumber,#email) <br>
         * 
         * @param lines 行文本序列
         * @param remove_inline_comments 是否移除行内注释。 true:移除,否则不移除
         * @return 命名sql 集合。
         */
        public static Map<String,String> parse2namedsqls(final Stream<String>lines,final boolean remove_inline_comments){
            
            final var namedsqls = new HashMap<String,String>();
            final var p = Pattern.compile("^([\\s-])*#\\s+([^\\s#]+)\\s*$");// key 标记
            final var p_comment = Pattern.compile("^([\\s]*)--.*$");// key 标记
            final var keys = new LinkedList<String>();
            final var values = new LinkedList<String>();
            
            // 添加key values
            final Supplier<Map<String,String>> add2namedsqls = ()->{
                if(keys.size()>0 && values.size()>0) {
                    final var k = keys.getLast();
                    namedsqls.put(k, String.join("\n", values));
                    keys.clear();
                    values.clear();
                }// keys 和 values 缓存框都给清空
                
                return namedsqls;// 命名SQL
            };
            
            // 逐行遍历
            lines.forEach(line->{
                if(line.matches("^\\s*$"))return;// 空白行过滤
                final var key_matcher = p.matcher(line);
                if(key_matcher.matches()) {
                    final var key = key_matcher.group(2);
                    add2namedsqls.get();
                    keys.add(key);

                }else {
                    if(p_comment.matcher(line).matches())return;
                    final var _line = remove_inline_comments // 是否移除行内注释
                        ? line.replaceAll("--\\s+.*$","") // 去除行内的尾部注释 ,由 --空格 引导的内容被省略掉。
                        : line;// 不移除行内注释
                    
                    values.add(_line);// 数据追加
                }//if (key_matcher.matches())
            });// lines.forEach
            
            // 添加剩余的SQL语句。
            add2namedsqls.get();
            
            // 返回结果集合
            return namedsqls;
        }
        
        /**
         * 提取参数名列表:
         * @param line 类似于 这样的sql 模板insert into ##tableName (name,password,sex,address,birth,phonenumber,email) <br>
         * values (#name,#password,#sex,#address,#birth,#phonenumber,#email),把 <br>
         * [#name,#password,#sex,#address,#birth,#phonenumber,#email],提取出来,注意提取后 井号被去除了。 <br>
         * 
         * @return 从模板提取出来的参数集合。
         */
        public static LinkedHashSet<String> retrieve_params(final String line) {
            
            final var placeholder = Pattern.compile("#+([a-z_][a-z0-9_]+)",
                Pattern.CASE_INSENSITIVE).matcher(line);
            final var params = new LinkedHashSet<String>();
            //提取所有位置参数
            while(placeholder.find()) params.add(placeholder.group(1));
            
            return params;
        }
        
        /**
         * namedsql_processor 对namedsqls中的‘{’,‘'’进行转义：防止MessageFormater把他误认为参数。 <br>
         * 注意:<br>
         * namedsql_processor_escape_brace的 preprocessor 只会对 namedsqls 中的所包含的语句进行处理,<br>
         * 并不会对 没有在namedsqls中存贮的sql语句调用preprocessor做预处理。<br>
         * 对于其他的传入的(比如直接传递,而不是采用方法反射,比如IJdbcSession.sql2records(sql)系列函数) <br>
         * 参见方法:IJdbcSession.sql2records(final String sqlpattern, final IRecord params) <br>
         * <br>
         * preprocessor 是不会对sql进行处理的,所以 如果需要调用 namedsql_processor 做参数
         * 填充,需要先手动的把sql进行进行预处理 <br>
         * 
         * @param namedsqls sql语句。 name->sql
         * @return SqlPatternPreprocessor
         */
        public static SqlPatternPreprocessor namedsql_processor_escape_brace(final Map<String, String> namedsqls) {

            return namedsql_processor(namedsqls, LittleTree::MFT_ESCAPE);
        }
        
        /**
         * namedsql_processor 对namedsqls中的‘{’进行转义：防止MessageFormater把他误认为参数。<br>
         * 注意:<br>
         * namedsql_processor的 preprocessor 只会对 namedsqls 中的所包含的语句进行处理,<br>
         * 并不会对 没有在namedsqls中存贮的sql语句调用preprocessor做预处理。<br>
         * 对于其他的传入的(比如直接传递,而不是采用方法反射,比如IJdbcSession.sql2records(sql)系列函数) <br>
         * 参见方法:IJdbcSession.sql2records(final String sqlpattern, final IRecord params) <br>
         * <br>
         * preprocessor 是不会对sql进行处理的,所以 如果需要调用 namedsql_processor 做参数
         * 填充,需要先手动的把sql进行进行预处理 <br>
         * 
         * @param namedsqls    sql语句 {(name,sql)}
         * @param preprocessor sql语句 的预处理器：例如对 neo4j的转义。
         * @return SqlPatternPreprocessor
         */
        public static SqlPatternPreprocessor namedsql_processor(final Map<String, String> namedsqls,
                final Function<String, String> preprocessor) {

            if (namedsqls != null)
                namedsqls.forEach((k, v) -> {// 依次处理每个SQL
                    namedsqls.compute(k, (key, value) -> preprocessor.apply(value));
                });// 依次处理每个SQL

            return namedsql_processor(namedsqls);
        }
        
        /**
         * 根据代理对象结构： 提取sharpPattern 中的数据操作语句 <br>
         * @param proxy 代理对象结构：一般是通过Jdbc.newInstance 调用一个未标记的接口函数，故意造成调用失败，致使Jdbc返回返回代理对象结构。
         * proxy内部包含，连接器，sqlpattern 解析器，一级后置收尾处理器，当前的数据库连接操作对象jdbc等 代理的内部结构，可以通过IRecord。都是
         * 作为单例的模式包装在IRecord 之中。因此可以通过的IRecordfindOne(Class<?>)的方式来提取，进而被使用。
         * @param sharpPattern sharppattern 的名称。如妹没有#开头，会自动添加一个#符号。作为标记。
         * @param params 占位符变量的 值定义容器{key->value}的集合。key 就是占位符的名称会根据 sharp占位符 "#(\\w+)" 的规则，即是否以井号
         * 开头的标识符号（identifier），来 对sharpPattern所标记SQL语句（也可以不是SQL遇见的一种DSL)提取，进而做值替换。随有点绕口，但是很简单。
         * @return pattern 所对应的数据操作语句。占位符变量也已经用params 做了替换。非数字类型会被自动的添加上 双引号“"”
         */
        public static String parseSharpPattern(final IRecord proxy,final String sharpPattern,
            final IRecord params) {
            
            if(proxy==null)return null;
            final var processor = proxy.findOne(SqlPatternPreprocessor.class);
            if(processor==null) return null;
            final var tpl = processor.handle(null,null,// 把processor 视作一个Map<String,String>的namedSql
                MFT(sharpPattern.startsWith("#")?"{0}":"#{0}",sharpPattern), null);// namesql 的模板
            if(tpl==null)return null;
            final var sql = substitute(tpl,"#+(\\w+)", params,// 对模板中的参数的位置 采用 params 中的数据来给予替换。
                (pat,t)-> pat.startsWith("##")
                ? t+"" // 对于以两个#开头的变量视作强制字符类型不加引号。
                : MFT(t instanceof Number?"{0,number,0}":"\"{0}\"",t));// 根据参数类型决定是否添加引号。
            
            return sql;
        }
        
        /**
         * 其实就是提取在方法Method上的标记比如annotation:JdbcQuery,JdbcExecute中的value 值。
         * 根据方法签名提取 对含有 井号#的pattern 进行侦测，如果侦测出来就用sharppattern_todetect所表标的内容，作为键值在
         * 在sharppattern_defs进行检索，并对method上的标记
         * 
         * @param method 方法方法对象，当sharppattern为null时，用于作为生成默认的sharppattern 名。
         * @param sharppattern 待检测的位于JdbcQuery中的以井号#开头的字符串 ,null 或是空白 表示 是# "#"+方法名称。
         * 例如对于方法  getName,sharppattern 为null,sharppattern则被视作#getName
         * @param sharppattern_defs 命名sharp pattern 的定义
         * @return 识别出来的 sharp pattern
         */
        public static String parseJdbcMethodSharpPattern(final Method method,final String sharppattern,
            final Map<String,String> sharppattern_defs) {
            
            final var sqlpattern= (sharppattern==null||sharppattern.matches("\\s*"))
                ?    "#"+method.getName()
                :    sharppattern;// 默认的sqlpattern为方法名
            final var sharp_matcher = Pattern.compile("#+([a-z_][a-z0-9_]+)",Pattern.CASE_INSENSITIVE)
                .matcher(sqlpattern);// namedsql 是一个用＃号作为前缀的名称
            if(!sharp_matcher.matches())return sqlpattern;// 非namedsql
            
            final var namedSqlpattern = sharppattern_defs.get(sharp_matcher.group(1));// 提取sqlpattern
            if(namedSqlpattern==null) {// namedsqls 中无法对应
                System.out.println(MFT("in {0} 无法对应到:{1}",method==null?"\"方法缺失\"":method.getName(),sqlpattern));
                return sqlpattern;// 
            }// if
            
            return namedSqlpattern;
        }
        
        /**
         * 生成一个命名sql(namedsql)的预处理器。 <br>
         * 对与双#号的参数不予进行替换 类型转换。 <br>
         * 
         * 一个典型使用 namedsql进行创建数据库接机口的案例是如下情形：<br>
         * 定义接口 <br>
         * interface UserDatabase { <br>
         * @JdbcExecute("#createTable") <br>
         * public void createTable(String tableName); <br>
         * }<br>
         * //提取命名SQL的集合。 <br>
         * var namedsqls = parse2namedsqls(utf8lines(new File(path("user.sql",UserModel.class)))); <br>
         * //生成接口的代理实例，并注入SqlPatternPreprocessor: 即namedsql_processor(namedsqls)的函数调用。 <br>
         * var database = Jdbc.newInstance(UserDatabase.class,jdbcConfig,namedsql_processor(namedsqls));<br>
         * //使用代理实例进行数据库操作。<br>
         * database.createTable()//  <br>
         * 
         * #createTable 是 user.sql 中的一条创建表的SQL语句。 <br>
         * 
         * 把如下的 命名sql 通常是来自于一个SQL文件。 <br>
         * -- -------------------------- <br>
         * -- # insertUser <br>
         * -- -------------------------- <br>
         * insert into ##tableName (name,password,sex,address,birth,phonenumber,email) <br>
         * values (#name,#password,#sex,#address,#birth,#phonenumber,#email) <br>
         *
         * 根据接口 <br>
         * @JdbcExecute({"#insertUser"}) <br>
         * public void  insertUser(String tableName,String name,String password,String sex,String address, <br>
         *  Date birth,String phonenumber,String email); <br>
         *
         * 给替换成 如下的式样 <br>
         * insert into {0} (name,password,sex,address,birth,phonenumber,email) <br>
         * values (''{1}'',''{2}'',''{3}'',''{4}'',''{5,date,yyyy-MM-dd HH:mm:ss}'',''{6}'',''{7}'') <br>
         * 
         * @param namedsqls 命名sql集合：{#key1->sql1,#key1->sql2,...}, 
         * @return 变换后的sqlapttern 可以被 MessageFormat处理的SQL语句。
         */
        public static SqlPatternPreprocessor namedsql_processor(final Map<String,String> namedsqls) {
            
            return (final Method method, final IRecord params, final String sqlpattern, final Jdbc jdbc)->{
                // 自动侦测SQL Pattern 或者 mehtod sharp pattern
                final var namedSqlpattern = parseJdbcMethodSharpPattern (method,sqlpattern,namedsqls);
                var line = namedSqlpattern;// 对namedSqlpattern 进行数据处理。
                if(method==null) return params!=null // 根据参数数据的不同进行数据变换
                    ? Jdbc.quote_substitute(line, "#+(\\w+)", params) // 采用参数sharpPattern进行数据替换
                    : line; // 不予进行方法参数回填。
                final var ai = new AtomicInteger(0);// 计数变量
                final var pp = method.getParameters();// 方法的参数集合
                for(final String key:params.keys()) {// 遍历方法参数。
                    final var i = ai.getAndIncrement();// 获取当前的参数位置
                    final var rawfmt = "{" + i + "}"; // 原始类型
                    final var type = pp[i].getType();// 获取参数类型
                    final var numfmt = "{" + i + ",number,#}"; // 数值格式
                    final var datefmt = "''{" + i + ",date,yyyy-MM-dd HH:mm:ss}''"; // 日期类型。
                    final var defaultfmt = "''{" + i + "}''"; // 默认格式
                    var isnumber = false; // 是否是数字格式
                    var isdate = false; // 是否是日期类型
                    var placeholder = defaultfmt;// 默认的占位符的式样，加上单引号
                    
                    if (Number.class.isAssignableFrom(type) || type == short.class || type == int.class
                            || type == long.class || type == float.class || type == double.class) { // 数值格式
                        placeholder = numfmt;
                        isnumber = true;
                    } else if (Date.class.equals(type)) { // 时间格式
                        isdate = true;
                        placeholder = datefmt;
                    } else { // 默认处理
                        // placeholder = defaultfmt;// 默认格式
                    }
                    
                    // 更新 sql模板,把参数名更换成位置序号
                    line = line.replace("##" + key, isnumber ? numfmt : isdate ? datefmt : rawfmt) // 数值格式
                               .replace("#" + key, placeholder); // 默认格式
                }// for
                
                // System.out.println(line);
                return line;// 返回处理后的sql 语句模板。
            };//(Method method,IRecord params,String sqlpattern,Jdbc jdbc)->
        }
        
        /**
         * SQL 的拦截器
         * 函数接口 String handle(Method method,IRecord params,String sqlpattern,Jdbc jdbc) 对
         * 请求的 sqlpattern 进行预处理。比如读写分离，分库分表的处理等。
         * -- method 方法对象,
         * -- params 参数列表:name->value,
         * -- sqlpattern sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,
         * -- jdbc 当前连接的数据库对象．
         * @author xuqinghua
         *
         * @param <T> 返回结果的类型
         */
        @FunctionalInterface
        public interface SqlInterceptor<T>{
            /**
             * 拦截器：如果结果返回null则给予放行,否则方法给予放行
             * @param method 方法对象
             * @param params 参数列表:name->value
             * @param sqlpattern sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力．
             * @param jdbc 当前连接的数据库对象．
             * @return 处理后的sql模板 
             */
            T intercept(final Method method,final IRecord params,final String sqlpattern,final Jdbc jdbc);
        }

        /**
         * jdbc 的事后处理。一般做一些收尾的拦截与
         *
         * @param <T> 返回结果的类型
         * @author xuqinghua
         */
        @FunctionalInterface
        public interface JdbcPostProcessor<T> {
            /**
             * 后续处理的方法
             *
             * @param result jdbc 的处理结果
             * @return <T> 先前的Jdbc的处理结果。这个类型是根据 接口返回类型而侦测出来的，一般不需要给予更改。
             */
            Object process(final Method method, final IRecord params, final Jdbc jdbc, final T result);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。 
         * 
         * @param <T> 访问接口 类的类型
         * @param itf 访问接口
         * @param jdbc 数据库访问接口
         * @param sqlpattern_preprocessor  sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．
         *  是一个(m,a,p,j)->p 的形式<br>
         *    method(m) 方法对象,<br>
         *    params(a args) 参数列表:name->value,<br>
         *    sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *    jdbc(j) 当前连接的数据库对象．<br>
         * @param sqlinterceptor SQL方法执行拦截器：需要注意 sqlinterceptor 是在 sqlpattern_preprocessor 处理之后才给予调用的。
         *    也就是说先调用sqlpattern_preprocessor，然后在调用sqlinterceptor;<br>
         *     method(m) 方法对象,<br>
         *    params(a args) 参数列表:name->value,<br>
         *    sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *    jdbc(j) 当前连接的数据库对象．<br>
         * @return 数据库访问的代理接口
         */
        public static synchronized <T> T newInstance(final Class<T> itf,final Jdbc jdbc,
            final SqlPatternPreprocessor sqlpattern_preprocessor,
            final SqlInterceptor<List<IRecord>> sqlinterceptor) {
            
            return newInstance(itf,jdbc,sqlpattern_preprocessor,
                sqlinterceptor,(JdbcPostProcessor<?> )null);
        }
        
        /**
         * 根据JDBC的上下文构建一个JDBC的执行环境。<br>
         * 创建一个接口itf的实现bean 根据注解信息来给予实现。<br> 
         * 
         * @param <T> 访问接口 类的类型
         * @param <U> jdbcPostProcessor的返回结果的类型
         * @param itf 访问接口 <br>
         * @param jdbc 数据库访问接口 <br>
         * @param sqlpattern_preprocessor  sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．<br>
         *  是一个(m,a,p,j)->p 的形式 <br>
         *    method(m) 方法对象, <br>
         *    params(a args) 参数列表:name->value, <br>
         *    sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *    jdbc(j) 当前连接的数据库对象．<br>
         * @param sqlinterceptor SQL方法执行拦截器：需要注意 sqlinterceptor 是在 sqlpattern_preprocessor 处理之后才给予调用的。<br>
         *    也就是说先调用sqlpattern_preprocessor，然后在调用sqlinterceptor;<br>
         *    method(m) 方法对象,<br>
         *    params(a args) 参数列表:name->value,<br>
         *    sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *    jdbc(j) 当前连接的数据库对象．<br>
         * @param jdbc_postprocessor 结果的后置处理处理器：对一般标准的处理结果进行后续处理。<br>
         * @return 数据库访问的代理接口
         */
        @SuppressWarnings("unchecked")
        public static synchronized <T,U> T newInstance(final Class<T> itf,final Jdbc jdbc,
            final SqlPatternPreprocessor sqlpattern_preprocessor, // sql 语句模板的处理
            final SqlInterceptor<List<IRecord>> sqlinterceptor,// jdbc的sql 执行拦截
            final JdbcPostProcessor<U> jdbc_postprocessor) { // jdbc_postprocessor 的jdbc处理结果最终递交。
            
            // 定义代码拦截器
            final SqlInterceptor<List<IRecord>> interceptor = // 方法的前置拦截器
                sqlinterceptor == null?(m,a,s,j)->null:sqlinterceptor;// 定义拦截器
            final JdbcPostProcessor<U> postprocessor = // jdbc 处理结果的最终 称帝的处理包装结果。
                jdbc_postprocessor==null?(m,a,j,r)->r:jdbc_postprocessor;// 定义后置处理器:默认不做处理e->e
            // 创建数据库操作的代理对象。
            final var t = (T)Proxy.newProxyInstance(itf.getClassLoader(),new Class<?>[] {itf},(proxy,method,args)->{
                /*对这里的程序设计做一点说明：考虑到各种语句Annotation的处理逻辑相似，这里我没有把他们分装成函数而是 统一的卸载一个函数里了
                 * 好处就是变量的共享非常方便：坏处就是 出现了多出口（postprocessor 出现的地方）。造成程序的理解混乱，但是由于注解不多，这种缺点还是
                 * 可以忍受的。所以就采用了这种混编程。*/
                
                
                ///////////////////////////////////////////////////////////////////////
                // 数据注入
                // 注入jdbc对象等环境对象．就像SpringMVC的请求参数的注入
                ///////////////////////////////////////////////////////////////////////
                final BiConsumer<Object[],Map<Class<?>,Object>> inject_default_values=(oo,mm)->{
                    if(oo!=null&&oo.length>0) {
                        final var tt = method.getParameterTypes();// 提取方法的参数列表
                        mm.forEach((cls,v)->{for(int i=0;i<tt.length;i++) 
                            if((tt[i] ==cls) && oo[i]==null)oo[i]=v;}// 根据参数类型进行注入。该位置的参数为null的时候给予注入。
                        );// foreach
                    }// oo!=null&&oo.length>0
                };// inject
                final var default_values = new HashMap<Class<?>,Object>();// Jdbc代理提供的默认参数列表。
                default_values.put(Jdbc.class, jdbc);// Jdbc的默认值
                
                
                ///////////////////////////////////////////////////////////////////////
                // 方法注释解析：JdbcQuery
                ///////////////////////////////////////////////////////////////////////
                //sql查询的执行
                final JdbcQuery[] jcqs = method.getAnnotationsByType(JdbcQuery.class);
                final SqlPatternPreprocessor pattern_preprocessor=sqlpattern_preprocessor==null
                    ? (m,a,p,j)->p:sqlpattern_preprocessor;// sql pattern 预处理。
                if(jcqs!=null && jcqs.length>0) {// 查询优先
                    final var o = handleJdbcQuery(jdbc,jcqs, method, args,pattern_preprocessor,interceptor);// 查询优先
                    // 默认方法的处理
                    if(isDefaultMethod(method)&& args.length>0 && args[args.length-1]==null) {
                        final Object oo[] = args.clone(); oo[oo.length-1] = o; //把查询结果作为参数列表的最后一位给予传递
                        inject_default_values.accept(oo,default_values);// 注入默认值
                        return postprocessor.process( method,params(method,args),jdbc,(U) // 结果呈递
                            invokeDefaultMethod(proxy,method,oo));
                    }// if isDefaultMethod
                    return postprocessor.process( method,params(method,args),jdbc,(U) // 结果呈递
                        o );
                }// if jcqs!=null
                
                
                ///////////////////////////////////////////////////////////////////////
                // 方法注释解析：JdbcPreparedQuery
                ///////////////////////////////////////////////////////////////////////
                //sql查询的执行:第二种jcq 这也是为何有个2的原因。s结尾表示这里复数的意思。
                final JdbcPreparedQuery[] jcq2s = method.getAnnotationsByType(JdbcPreparedQuery.class);
                // 这一段代码是一种示例：用于演示每个annotaion 都可以自定义 SqlPatternPreprocessor,其实与采用pattern_preprocessor效果一样
                final SqlPatternPreprocessor pattern_preprocessor2=sqlpattern_preprocessor==null
                    ? (m,a,p,j)->p:sqlpattern_preprocessor;// 演示使用一个专用的 pattern_preprocessor2 
                if(jcq2s!=null && jcq2s.length>0) {// 查询优先
                    final var o = handleJdbcPreparedQuery(jdbc,jcq2s, method, args,pattern_preprocessor2,
                        interceptor);// 查询优先
                    // 默认方法的处理
                    if(isDefaultMethod(method)&& args.length>0 && args[args.length-1]==null) {
                        final Object oo[] = args.clone(); oo[oo.length-1] = o; //把查询结果作为参数列表的最后一位给予传递
                        inject_default_values.accept(oo,default_values);// 注入默认值
                        return postprocessor.process( method,params(method,args),jdbc,(U) // 结果呈递
                            invokeDefaultMethod(proxy,method,oo));
                    }// if isDefaultMethod
                    return postprocessor.process( method,params(method,args),jdbc,(U) // 结果呈递
                        o );
                }// if jcqs!=null
                
                
                ///////////////////////////////////////////////////////////////////////
                // 方法注释解析：JdbcExecute
                ///////////////////////////////////////////////////////////////////////
                // SQL语句的执行:JdbcExecute
                final JdbcExecute[] jces = method.getAnnotationsByType(JdbcExecute.class);
                synchronized (jdbc){//保持执行操作同步运行．
                    if(jces!=null && jces.length>0)return
                        postprocessor.process( method,params(method,args),jdbc,(U) // 结果呈递
                            handleJdbcExecute(jdbc,jces, method, args,pattern_preprocessor,interceptor));
                }// synchronized (jdbc)
                
                
                ///////////////////////////////////////////////////////////////////////
                // 方法注释解析：PreparedExecute
                ///////////////////////////////////////////////////////////////////////                
                // SQL语句的执行:PreparedExecute
                final JdbcPreparedExecute[] jce2s = method.getAnnotationsByType(JdbcPreparedExecute.class);
                synchronized (jdbc){//保持执行操作同步运行．
                    if(jce2s!=null && jce2s.length>0)
                        return postprocessor.process( method,params(method,args),jdbc,(U) // 结果呈递
                            handlePreparedExecute(jdbc,jce2s,method,args,pattern_preprocessor,interceptor));
                }// synchronized (jdbc)

                
                ///////////////////////////////////////////////////////////////////////
                // 方法注释解析：默认方法  -没有注释但是默认方法
                ///////////////////////////////////////////////////////////////////////    
                // 如果以上的注解都没有处理成功，尝试执行函数的默认方法：默认函数的处理
                if(isDefaultMethod(method))
                    return postprocessor.process( method,params(method,args),jdbc,(U) // 结果呈递
                        Jdbc.handleDefaultMethod(proxy, method, args, jdbc));
                
                
                ///////////////////////////////////////////////////////////////////////
                // 方法注释解析：Jdbc所不能理解的方法
                ///////////////////////////////////////////////////////////////////////
                final var params = params(method,args);
                final var message = MFT(
                    "方法：{0},参数:{1}，超出了Jdbc所能理解的范围，代理失败。但是这个方法会把代理的对象的结构信息也给返回出去，\n"
                    + "可以作为访问:sqlinterceptor，sqlpattern_preprocessor，jdbc_postprocessorjdbc等对象的一个入口。",
                    method.getName(),params);
                
                U u = null;// 默认的返回值
                // 仅当方法的返回值类型为IRecord 系列的时候才提供全面代理结构的信息作为返回值。
                if(method.getReturnType().isAssignableFrom(IRecord.class)) {
                    try {
                        u = (U)(Object)REC(// 返回结果结构
                            "success",false,// 标记执行失败
                            "message",message,// 提示消息内容
                            "params",params,// 调用的参数
                            "method",method,// 执行失败的额方法
                            "sqlinterceptor",sqlinterceptor,
                            "sqlpattern_preprocessor",sqlpattern_preprocessor,
                            "jdbc_postprocessor",jdbc_postprocessor,
                            "jdbc",jdbc //jdbc 的连接对象
                        );// 返回当前的执行环境。;
                    }catch(Exception e) {
                        e.printStackTrace();
                    }// try
                } else {// if(method.getReturnType().isAssignableFrom(IRecord.class)) 
                    System.err.println("返回类型非:IRecord，不予提供 代理详情结构信息：\n"+message);
                }//  if(method.getReturnType().isAssignableFrom(IRecord.class))
                
                // 以上均处理不了，折返回null 作为处理失败的结果。
                // 方法的计算结果，与 下面的 return t 是不一样的，return t 是代理对象，而这里是方法的运算结果。
                return postprocessor.process( method,params,jdbc,(U) u);
                
            });// newProxyInstance
            
            return t;// 返回T类型的代理对象。
        }

        /**
         * 处理默认的构造方法<br>
         * 注意invoke 与  handleDefaultMethod的区别是 handleDefaultMethod会 左接口的参数方法注入。<br>
         * 而 invokeDefaultMethod 则不会。 所 handleDefaultMethod 需要传递Jdbc 参数<br>
         *
         * @param proxy  代理对象
         * @param method 方法对象
         * @param args   方法参数对象数组
         * @param jdbc   jdbc对象
         * @return 默认方法的执行结果
         */
        public static Object handleDefaultMethod(final Object proxy,final Method method,
            final Object[]args,final Jdbc jdbc) {
            
            if(jdbc==null)return null;
            
            // 数据注入,注入jdbc对象等环境对象．
            final BiConsumer<Object[],Map<Class<?>,Object>> inject=(oo,mm)->{
                if(oo!=null&&oo.length>0) {
                    var tt = method.getParameterTypes();
                    mm.forEach((cls,v)->{for(int i=0;i<tt.length;i++) 
                        if((tt[i] ==cls) && oo[i]==null)oo[i]=v;}
                    );// foreach
            }};// inject
            
            final var mm = new HashMap<Class<?>,Object>();mm.put(Jdbc.class, jdbc);
            inject.accept(args,mm);
            final boolean isTransaction = Arrays.stream(method.getParameterTypes())
                .anyMatch(e->e==IJdbcSession.class);// IJdbcSession对象作为是否为事务操作的标记。
            // 封装trycatch,trycach 的编码真的很占地方：哈哈啥
            final Supplier<Object> sp = () -> {
                Object obj = null;// 返回值
                try {obj = invokeDefaultMethod(proxy,method,args);}// 调用默认处理
                catch(Throwable e) {e.printStackTrace();}
                return obj;// 返回默认值的处理结果
            };// sp 结果生成器
            
            // 返回结果
            return isTransaction // 是否存在事务处理
            ? jdbc.withTransaction( sess -> { // 执行事务
                    mm.put( IJdbcSession.class, sess );// 准备sess会话对象
                    inject.accept(args,mm);// 把sess事务对象注入到参数上下文中
                    //System.out.println(Arrays.asList(args));
                    invokeDefaultMethod(proxy,method,args); 
              }) // withTransaction
            : sp.get(); // 非事务操作
        }

        /**
         * 调用接口默认方法：<br>
         * 注意invoke 与  handleDefaultMethod的区别是 handleDefaultMethod会 左接口的参数方法注入。<br>
         * 而 invokeDefaultMethod 则不会。 <br>
         *
         * @param proxy  代理对象
         * @param method 方法名
         * @param args   参数名
         * @return 调用默认方法．
         * @throws Throwable
         */
        private static Object invokeDefaultMethod(final Object proxy, final Method method, final Object[] args)
                throws Throwable {

            final var declaringClass = method.getDeclaringClass();
            final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(declaringClass,
                    MethodHandles.lookup());// 确定似有方法寻找工具
            return lookup.unreflectSpecial(method, declaringClass)
                    .bindTo(proxy)// 防止对proxy的第归调用．
                    .invokeWithArguments(args);
        }

        /**
         * 判断是否是默认方法<br>
         *
         * @param method 方法对象
         * @return true default method 否则 非默认函数
         */
        private static boolean isDefaultMethod(final Method method) {

            return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC |
                    Modifier.STATIC)) == Modifier.PUBLIC) && method.getDeclaringClass().isInterface();
        }

        /**
         * 装配方法参数:形参数->实参数<br>
         *
         * @param method 方法对象
         * @param args   实际参数对象集合
         * @return 参数的key-value 集合
         */
        private static IRecord params(final Method method, final Object[] args) {

            final var pp = method.getParameters();
            final var map = new LinkedHashMap<String, Object>();// 命名参数:需要注意这里采用LinkedHashMap以保持原来参数的顺序。
            for (int i = 0; i < pp.length; i++) map.put(pp[i].getName(), args[i]);

            return new LinkedRecord(map);
        }

        /**
         * 执行的处理：
         * <p>
         * 对于一个换行位含有;sql会自动尽心拆分即：<br>
         * 对于一个 这样的sqlpattern：<br>
         * drop table if exists t_aaa;<br>
         * create table t_aaa(id int)<br>
         * 会视作两条sql 语句<br>
         *
         * @param jdbc                 jdbc对象
         * @param jces                 jdbc的执行语句集合
         * @param method               调用方法
         * @param args                 调用参数
         * @param pattern_preprocessor sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．<br>
         * @param sqlinterceptor       SQL方法执行拦截器：需要注意 sqlinterceptor 是在 sqlpattern_preprocessor 处理之后才给予调用的。<br>
         *                             也就是说先调用sqlpattern_preprocessor，然后在调用sqlinterceptor;<br>
         *                             method(m) 方法对象,<br>
         *                             params(a args) 参数列表:name->value,<br>
         *                             sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *                             jdbc(j) 当前连接的数据库对象．
         * @return 执行结果
         */
        private static Object handleJdbcExecute(final Jdbc jdbc, final JdbcExecute[] jces,
                final Method method, final Object[] args, final SqlPatternPreprocessor pattern_preprocessor,
                final SqlInterceptor<List<IRecord>> sqlinterceptor) {
            
            //非法的执行SQL语句则直接返回
            if (jces == null || jces.length < 1) return null;

            final var _patterns = jces[0].value();// sql语句模板数组
            final String[] patterns = (_patterns == null || _patterns.length < 1)
                    ? new String[]{null} : _patterns; //  没有传入sqlpattern 代表一个采用默认 pattern 需要用pattern_preprocessor 来解析。
            final var pargs = params(method, args);//构造参数对象
            return jdbc.withTransaction(sess -> {// 开启事务管理
                for (var pattern : patterns) { // sql语句模板 :当pattern 为null的时候，pattern_preprocessor 会为其左方法签名的解释。不过需要namedsql_processor配置。
                    final var dd = sqlinterceptor.intercept(method, pargs, pattern, jdbc);
                    if (dd != null) continue;// 非空表示拦截
                    // 提取SQL语句模板,会自动为 null的pattern 提供方法签名的解释
                    final var sqlPattern = pattern_preprocessor.handle(method, pargs, pattern, jdbc);
                    final var sqlLines = MessageFormat.format(sqlPattern, args);// 提取SQL语句,并添加参数
                    if (sqlLines == null) {// 方法的SQL语句模板解释失败
                        throw new Exception(MFT(
                            "无法为方法{0}解析出正确的SQL语句，请确保为Jdbc对象安装了正确的pattern_preprocessor!",
                            method.getName()));
                    }// lines
                    final String[] sqls = sqlLines.split(";\\s*\n+");// 尝试对sqls 进行多语句解析。位于行末的分号给予分解
                    for (final var sql : sqls) {// 依次执行SQL语句
                        if (sql.matches("\\s*")) continue;
                        if (debug) System.out.println("jdbc:handleJdbcQuery:" + sql);
                        sess.sql2execute2int(sql);
                    }// for sql:sqls
                }//for var pattern:patterns
            });// withTransaction
            
        } // handleJdbcExecute

        /**
         * 对于一个换行位含有;sql会自动尽心拆分即：<br>
         * 对于一个 这样的sqlpattern：<br>
         * drop table if exists t_aaa; <br>
         * create table t_aaa(id int) <br>
         * 会视作两条sql 语句 <br>
         * <p>
         * sqlpattern 和sqltpl 的区别就是<br>
         * sqlpattern 是{0},{1},等 MessageFormat 格式的模板，用于匹配 参数 <br>
         * sqltpl 是sqlpattern被解析后的结果，其中的参数是 ?的占位符，用于对PreparedStatement的处理。 <br>
         * 执行的处理<br>
         *
         * @param jdbc                 jdbc对象
         * @param jces                 jdbc的执行
         * @param method               调用方法
         * @param args                 调用参数
         * @param pattern_preprocessor sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．
         * @param sqlinterceptor       SQL方法执行拦截器：需要注意 sqlinterceptor 是在 sqlpattern_preprocessor 处理之后才给予调用的。
         *                             也就是说先调用sqlpattern_preprocessor，然后在调用sqlinterceptor;
         *                             method(m) 方法对象,
         *                             params(a args) 参数列表:name->value,
         *                             sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,
         *                             jdbc(j) 当前连接的数据库对象．
         * @return 执行结果
         */
        private static Object handlePreparedExecute(final Jdbc jdbc, final JdbcPreparedExecute[] jces,
                final Method method, final Object[] args, final SqlPatternPreprocessor pattern_preprocessor,
                final SqlInterceptor<List<IRecord>> sqlinterceptor) {

            if (jces == null || jces.length < 1) return null;

            final var _patterns = jces[0].value();// sql语句模板数组
            final String[] patterns = (_patterns == null || _patterns.length < 1)
                    ? new String[]{null} : _patterns; //  没有传入sqlpattern 代表一个采用默认 pattern 需要用pattern_preprocessor 来解析。
            final var pargs = params(method, args);//构造参数对象
            return jdbc.withConnection(conn -> {// 开启事务管理
                for (var pattern : patterns) {// sql语句模板 :当pattern 为null的时候，pattern_preprocessor 会为其左方法签名的解释。不过需要namedsql_processor配置。
                    final var dd = sqlinterceptor.intercept(method, pargs, pattern, jdbc);
                    if (dd != null) continue;// 非空表示拦截
                    //// 提取SQL语句模板,会自动为 null的pattern 提供方法签名的解释
                    final var patternLines = pattern_preprocessor.handle(method, pargs, pattern, jdbc);
                    if (patternLines == null) {// 方法的SQL语句模板解释失败
                        throw new Exception(MFT(
                                "无法为方法{0}解析出正确的SQL语句，请确保为Jdbc对象安装了正确的pattern_preprocessor!",
                                method.getName()));
                    }// lines
                    final String[] tpl_patterns = patternLines.split(";\\s*\n+");// 尝试对sqls 进行多语句解析，位于行末的分号给予分解
                    for (final var tpl_pattern : tpl_patterns) {// 依次执行SQL语句
                        if (tpl_pattern.matches("\\s*")) continue;
                        final var sqltpl = MessageFormat.format(tpl_pattern, args);// 提取SQL语句
                        if (debug) System.out.println("jdbc:handleJdbcQuery:" + sqltpl);
                        final var pstmt = pudt_stmt(conn, sqltpl);
                        jdbc.pstmt_execute_throws(pstmt, sqltpl.contains("?") ? args : null, true);
                    }// for sql:sqls
                }//for var pattern:patterns

                return true;
            });// withTransaction
        }

        /**
         * 查询的处理：通用查询，由具体俄查询分析工
         *
         * @param jdbc    jdbc对象
         * @param queryer 具体的查询器：handleJdbcQuery，handleJdbcPreparedQuery
         * @param method  调用方法
         * @param args    调用参数
         * @return SQL 查询结果
         */
        private static Object handleGenericQuery(final Jdbc jdbc, final Supplier<List<IRecord>> queryer,
                final Method method, final Object[] args) {

            final Class<?> retCls = method.getReturnType();// 返回类型
            //System.out.println(retCls.getName());
            final List<IRecord> recs = queryer.get();// 数据查询

            // 集合类型数据处理：判断结果的依旧就返回值是Collection 则为集合，否则就是单值
            if (Collection.class.isAssignableFrom(retCls)) {// 集合类型数据处理：是否单值
                return recs;
            } else {//单个值：则尝试进行左类型转换。
                final IRecord rec = recs != null && recs.size() > 0 ? recs.get(0) : null;// 不存在则返回null
                return IRecord.rec2obj(rec, retCls);// 把单个record 转传承目标类型。
            }//if
        }

        /**
         * 查询的处理
         *
         * @param jdbc                 jdbc对象
         * @param jcqs                 jdbc的查询
         * @param method               调用方法
         * @param args                 调用参数
         * @param pattern_preprocessor sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．
         * @param sqlinterceptor       SQL方法执行拦截器：需要注意 sqlinterceptor 是在 sqlpattern_preprocessor 处理之后才给予调用的。<br>
         *                             也就是说先调用sqlpattern_preprocessor，然后在调用sqlinterceptor;<br>
         *                             method(m) 方法对象,<br>
         *                             params(a args) 参数列表:name->value,<br>
         *                             sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *                             jdbc(j) 当前连接的数据库对象．<br>
         * @return SQL 查询结果
         */
        private static Object handleJdbcQuery(final Jdbc jdbc, final JdbcQuery[] jcqs,
                final Method method, final Object[] args, final SqlPatternPreprocessor pattern_preprocessor,
                final SqlInterceptor<List<IRecord>> sqlinterceptor) {

            //非法参数直接返回
            if (jcqs == null || jcqs.length < 1) return null;

            //通用jdbc 查询
            return Jdbc.handleGenericQuery(jdbc, () -> {
                final var params = params(method, args);
                final var oo = sqlinterceptor.intercept(method, params, jcqs[0].value(), jdbc);
                if (oo != null) return (List<IRecord>) oo;// 方法截取

                final var pattern = pattern_preprocessor.handle(method,
                        params(method, args), jcqs[0].value(), jdbc);// 模式处理
                final var sql = MessageFormat.format(pattern, args);// SQL语句组装
                if (debug) System.out.println("jdbc:handleJdbcQuery:" + sql);// 调试信息
                List<IRecord> recs = new LinkedList<>();
                try {
                    recs = jdbc.sql2records_throws(sql);// 执行SQL查询
                } catch (Exception e) {
                    final var new_param = params.aoks2rec(k -> params.get(k) instanceof Number ? "##" + k : "#" + k);
                    final var new_sql = Term.FT(sql, new_param);
                    recs = jdbc.sql2records(new_sql);// 执行SQL查询
                }// try
                
                // 结果返回
                return recs;
            }, method, args);// handleGenericQuery
        }

        /**
         * 查询的处理<br>
         *
         * @param jdbc                 jdbc对象
         * @param jcq2s                jdbc的查询
         * @param method               调用方法
         * @param args                 调用参数
         * @param pattern_preprocessor sql语句pattern预处理：比如对于特征占位符个与替换，特别是datasharding的分数据分表．<br>
         * @param sqlinterceptor       SQL方法执行拦截器：需要注意 sqlinterceptor 是在 sqlpattern_preprocessor 处理之后才给予调用的。<br>
         *                             也就是说先调用sqlpattern_preprocessor，然后在调用sqlinterceptor;<br>
         *                             method(m) 方法对象,<br>
         *                             params(a args) 参数列表:name->value,<br>
         *                             sqlpattern(p pattern) sql模板 ，sql 模板通称会携带模板参数，以完成分数据库，分表的能力,<br>
         *                             jdbc(j) 当前连接的数据库对象．<br>
         * @return SQL 查询结果
         */
        private static Object handleJdbcPreparedQuery(final Jdbc jdbc, final JdbcPreparedQuery[] jcq2s,
                final Method method, final Object[] args, final SqlPatternPreprocessor pattern_preprocessor,
                final SqlInterceptor<List<IRecord>> sqlinterceptor) {

            //条件检测
            if (jcq2s == null || jcq2s.length < 1) return null;

            //通用查询
            return Jdbc.handleGenericQuery(jdbc, () -> {
                final var params = params(method, args);
                final var oo = sqlinterceptor.intercept(method, params, jcq2s[0].value(), jdbc);
                if (oo != null) return oo;// 方法截取

                final var preparedSqlpattern = pattern_preprocessor.handle(method, params,
                        jcq2s[0].value(), jdbc);
                final var preparedSql = MessageFormat.format(preparedSqlpattern, args);// SQL语句组装
                if (debug) System.out.println("jdbc:handleJdbcQuery2:preparedsql" + preparedSql);
                final var recs = jdbc.precords(preparedSql, args);// prepared SQL 执行查询

                // 检索结果返回
                return recs;
            }, method, args);// handleGenericQuery
        }
        
        /**
         * 值替换的时候 自动为值添加商英文双引号“"”，但是对于以double sharp 开头的pat 不予添加引号。<br>
         * 用params中的值替换line中的各种pattern的内容。<br>
         * 
         * 示例：quote_substitute("添加引号:#name,不添加引号 :##name", "#+(\\w+)",REC("name","肥大细胞"))返回 <br>
         * 添加引号:"肥大细胞",不添加引号 :肥大细胞 <br>
         * 
         * @param line 待解析的行数据
         * @param pattern 变量名的pattern
         * @param params 变量的定义：{name->value}
         * @return 解析后的结果
         */
        public static String quote_substitute(final String line,final String pattern,
            final IRecord params) {
            final Function<Object, Object> mapper = (o) -> {
                final var clazz = o == null ? Objects.class : o.getClass();
                if (o instanceof Date) {
                    return CronTime.sdf.format((Date) o);
                } else if (o instanceof LocalTime) {
                    return CronTime.sdf.format(CronTime.lt2dt((LocalTime) o));
                } else if (o instanceof LocalDate) {
                    return CronTime.sdf.format(CronTime.ld2dt((LocalDate) o));
                } else if (o instanceof LocalDateTime) {
                    return CronTime.sdf.format(CronTime.ldt2dt((LocalDateTime) o));
                } else if(Number.class.isAssignableFrom(clazz)
                        || clazz == short.class || clazz == int.class
                        || clazz == long.class || clazz == float.class
                        || clazz == double.class){
                    return o+"";
                }else {
                    return o;
                } //if
            };//  变换函数

            return substitute(line, Pattern.compile(pattern), params,
                    (pat, e) -> MFT(!pat.startsWith("##") ? "\"{0}\"" : "{0}", mapper.apply(e))
            );
        }
        
        /**
         * 值替换的时候 自动为值添加商英文双引号“"”，但是对于以double sharp 开头的pat 不予添加引号。
         * 用params中的值替换line中的各种pattern的内容。 但是对于以double sharp 开头的pat 不予添加引号。
         * 
         * 示例：quote_substitute("添加引号:#name,不添加引号 :##name", "#+(\\w+)",REC("name","肥大细胞"))返回
         * 添加引号:"肥大细胞",不添加引号 :肥大细胞
         * 
         * @param line 待解析的行数据
         * @param pattern 变量名的pattern
         * @param params 变量的定义：{name->value}
         * @return 解析后的结果
         */
        public static String quote_substitute(final String line,final Pattern pattern,
            final IRecord params) {
            
            return substitute(line, pattern, params,
                (pat,e)->!pat.startsWith("##")?MFT("\"{0}\"",e+""):e+""
            );
        }
        
        /**
         * 简单替换 <br>
         * 用params中的值替换line中的各种pattern的内容。不会添加任何 辅助标记，比如引号。<br>
         * 
         * @param line 待解析的行数据
         * @param pattern 变量名的pattern
         * @param params 变量的定义：{name->value}
         * @return 解析后的结果
         */
        public static String substitute(final String line,final String pattern,
            final IRecord params) {
            
            return substitute(line, Pattern.compile(pattern), params,  (pat,e)->e+"");
        }

        /**
         * 简单替换 <br>
         * 用params中的值替换line中的各种pattern的内容。不会添加任何 辅助标记，比如引号。<br>
         *
         * @param line    待解析的行数据
         * @param pattern 变量名的pattern
         * @param params  变量的定义：{name->value}
         * @return 解析后的结果
         */
        public static String substitute(final String line,final Pattern pattern,
            final IRecord params) {
            return substitute(line, pattern, params, (pat,e)->e+"");
        }

        /**
         * 模式替换：带有回调函数，可以进行替换值的自定义。<br>
         * <p>
         * 示例：<br>
         * var t = Jdbc.substitute("hello #your_name i am #my_name","#(\\w+)",<br>
         * REC("your_name","张三","my_name","李四"),(e)->e+"!");<br>
         * 返回:hello 张三! i am 李四!<br>
         * <p>
         * 用params中的值替换line中的各种pattern的内容。<br>
         *
         * @param line     待解析的行数据
         * @param pattern  变量名的pattern
         * @param params   变量的定义：{name->value}
         * @param callback 二元函数：使用params中的值替换pattern结构的变量的时候，对值的操作函数。把对象转换成字符串的方法。<br>
         *                 (pat,value)->String, pat 是匹配的模式的字符串,value 是在params 与 pat 中的key 为 pat的
         *                 group(1)的数据值。
         * @return 解析后的结果
         */
        public static <T> String substitute(final String line, final String pattern,
                final IRecord params, BiFunction<String, T, String> callback) {
            
            return Jdbc.substitute(line, Pattern.compile(pattern), params, callback);
        }

        /**
         * 模式替换：带有回调函数，可以进行替换值的自定义。<br>
         * <p>
         * 用params中的值替换line中的各种pattern的内容。<br>
         * <p>
         * 例如：
         * 一段 line: hello #your_name i am #my_name 的一段文字。<br>
         * 使用 pattern: "#(\\w+)" 在 REC("your_name","张三","my_name","李四")进行替换, <br>
         * callback :e->e+"!"<br>
         * 就会返回：<br>
         * hello 张三！i am 李四！<br>
         *
         * @param line     待解析的行数据
         * @param pattern  变量名的pattern,必须在pattern中使用分组标识出：pattern 标识的变量名称！ 否则就会之际返回
         * @param params   变量的定义：{name->value}, 对于满足line中的pattern,但是尚未再params找到对应值的数据，将其给予再line中删除，即替换为空白。
         * @param callback 二元函数：使用params中的值替换pattern结构的变量的时候，对值的操作函数。把对象转换成字符串的方法。<br>
         *                 (pat,value)->String, pat 是匹配的模式的字符串,value 是在params 与 pat 中的key 为 pat的 <br>
         *                 group(1)的数据值。
         * @return 解析后的结果，对于满足line中的pattern,但是尚未再params找到对应值的数据，将其给予再line中删除，即替换为空白。
         */
        @SuppressWarnings("unchecked")
        public static <T> String substitute(final String line, final Pattern pattern,
                final IRecord params, BiFunction<String, T, String> callback) {
            
            var matcher = pattern.matcher(line);
            var _line = line;
            var times = 10000;// 最大的替换次数
            while (matcher.find()) {
                if (times <= 0) {
                    System.err.println("替换次数超过1000次，给予终止替换");
                }
                if (matcher.groupCount() < 1) {
                    System.err.println("必须在pattern中使用分组标识出：pattern 标识的变量名称！");
                    return line;// 
                }// if
                final var key = matcher.group(1);// 提取pattern所标识的变量
                final var value = params.get(key);// 提取该pattern所标识的变量的值。
                final var s = callback.apply(matcher.group(), (T) value);// 获取替换值的字符串标识。
                _line = matcher.replaceFirst(s == null ? "" : s);// 更新此次匹配的结果
                matcher = pattern.matcher(_line);
            }// while

            return _line;// 结果返回
        }

        /**
         * 从clazz 对象中寻找一个名字叫做 name的方法
         *
         * @param clazz 类对象
         * @param name  方法名称的字符串表示
         * @return 方法对象
         */
        public static Method methodOf(final Class<?> clazz, final String name) {
            return Arrays.stream(clazz.getDeclaredMethods())
                    .filter(e -> e.getName().equals(name)).findFirst().get();
        }

        /**
         * 快速构造一个Map&ltObject,Object&gt的对象:快送构造Map的方法
         *
         * @param oo key1,value1,key2,value2的序列
         * @return Map&ltObject,Object&gt的对象
         */
        public static Map<Object, Object> M(final Object... oo) {
            final var map = new LinkedHashMap<>();
            if (oo != null && oo.length > 0) {
                for (int i = 0; i + 1 < oo.length; i += 2) {
                    map.put(oo[i], oo[i + 1]);
                }//for
            }//if
            return map;
        }

        /**
         * 创建jdbc连接对象
         */
        public void init(final String driver, final String url, final String user, final String password) {
            this.supplierConn = () -> {// 自己提供数据库连接
                Connection conn = null;// 数据库连接
                try {
                    final Class<?> cls = (null != driver) ? Class.forName(driver) : null;
                    if (cls == null) {
                        System.err.println("数据库驱动:\"" + driver + "\"加载失败!");
                        return null;
                    }
                    conn = DriverManager.getConnection(url, user, password);
                } catch (Exception e) {
                    System.err.println(MessageFormat.format(
                            "jdbc connection error for,driver:{0},url:{1},user:{2},password:{3}",
                            driver, url, user, password));
                    e.printStackTrace();
                }//try
                return conn;
            };// 连接构造其
        }

        /**
         * 目前只支持mysql，为了防止意外发生，不提供表删除操作
         *
         * @param tableName 表名,不能带有数据库名：即不能出现dbname.tblename这样的全路径名，而只能为tblename的相对路径名。
         * @return 表格存在 返回 true,表格不存在返回false
         */
        public boolean tblExists(final String tableName) {
            return this.sql2records("show tables like '" + tableName + "'").size() > 0;
        }

        /**
         * 目前只支持mysql
         *
         * @param database 数据库名
         * @return 数据库存在 返回 true,数据库不存在返回false
         */
        public boolean dbExists(final String database) {
            return this.sql2records("show databases like '" + database + "'").size() > 0;
        }

        /**
         * 目前只支持mysql
         *
         * @param tableName 表名
         * @param defs      表定义
         * @return 执行状态标记  true if the first result is a ResultSet object; false if it is an update count or there are no results
         */
        public boolean createTable(final String tableName, final String defs) {
            String sql = MessageFormat.format("create table {0} ( {1} ) ", defs);
            return this.sqlexecute(sql);
        }

        /**
         * 目前只支持mysql
         *
         * @param tableName 表名
         * @param defs      表定义的各个字段定义[如 name varchar(32)]序列 会采用逗号进行字段连接
         * @return 执行状态标记  true if the first result is a ResultSet object; false if it is an update count or there are no results
         */
        public boolean createTable(final String tableName, final String... defs) {
            String sql = MessageFormat.format("create table {0} ( {1} ) ",
                    tableName, String.join(",", Arrays.asList(defs)));
            return this.sqlexecute(sql);
        }

        /**
         * 目前只支持mysql
         *
         * @param tableName 表名
         * @param defs      表定义的各个字段定义[如 name varchar(32)]序列 会采用逗号进行字段连接
         * @return 执行状态标记  true if the first result is a ResultSet object; false if it is an update count or there are no results
         */
        public boolean createTableIfNotExists(final String tableName, final String... defs) {
            if (this.tblExists(tableName)) return false;
            final String sql = MessageFormat.format("create table {0} ( {1} ) ",
                    tableName, String.join(",", Arrays.asList(defs)));
            if (debug) System.out.println("jdbc:createTableIfNotExists:" + sql);
            return this.sqlexecute(sql);
        }

        /**
         * 获得数据库连接:每次都是重新创建一个数据库连接．
         *
         * @return 数据库连接
         */
        public Connection getConnection() {
            final Connection conn = supplierConn.get();
            return conn;
        }

        /**
         * 執行sql
         *
         * @param sql 更新操作的sql语句：update,delete,drop 等
         * @return 执行状态标记  true if the first result is a ResultSet object; false if it is an update count or there are no results
         */
        public boolean sqlexecute(final String sql) {
            return psqlexecute(sql, (Map<Integer, Object>) null);
        }

        /**
         * 執行sql
         *
         * @param sql 更新操作的sql语句：update,delete,drop 等
         * @return 执行状态标记  true if the first result is a ResultSet object; false if it is an update count or there are no results
         */
        public boolean psqlexecute(final String sql, final Map<Integer, Object> params) {
            return psqlexecute(sql, params, this.getConnection(), true);
        }

        /**
         * 执行SQL语句不考虑对原有的数据的做的变化：
         *
         * @param sql 更新操作的sql语句：update,delete,drop 等
         * @param oo  参数数组
         * @return 执行状态标记  true if the first result is a ResultSet object; false if it is an update count or there are no results
         */
        public boolean psqlexecute(final String sql, final Object[] oo) {
            final Map<Integer, Object> params = new HashMap<>();
            if (oo != null) for (int i = 0; i < oo.length; i++) params.put(i + 1, oo[i]);
            return psqlexecute(sql, params, this.getConnection(), true);
        }

        /**
         * 對查詢結果進行操作
         * @author gbench
         *
         * @param <T>
         */
        public interface QueryHandler<T>{
            /**
             * 對查詢結果進行處理（結果已經被生成道了rs之中）
             * @param conn 數據庫練級 通常不需要操作
             * @param stmt 查詢語句  通常不需要操作
             * @param rs 返回結果
             * @param rsm 結果信息結構
             * @param n 結果列數
             * @return 處理結果
             */
            T handle(final Connection conn, final Statement stmt,
                     final ResultSet rs, final ResultSetMetaData rsm, final int n) throws SQLException;
        }

        /**
         * 一次事务性的会话：共享一个数据库连接，并且出现操作失败（sql操作)，将给予先前的动作回滚．<br>
         * IJdbcSession 将作为一个Monad来出现。它内部保存由会话过程的状态数据。D 类型的data <br>
         * 用来作为链式编程的 特有编写方法。<br>
         * 
         * IJdbcSession 专门定义了一套jdbc的操作函数。这些函数的操作不会关闭数据库连接。所以 <br>
         * 当需要进行一些列共享数据库连接的操作的时候，可以使用 带有IJdbcSession 的函数来进行操作 <br>
         * 比如Jdbc.withTransaction的系列函数。
         *
         * @author xuqinghua
         *
         * @param <T> transCode，即SessionId的类型．又叫事务编号
         * @param <D> Data，Session 中的数据类型。又叫Monad session 的状态数据。
         */
        public interface IJdbcSession<T,D>{

            /**
             * 获取数据库连接
             *
             * @return 数据库连接
             */
            Connection getConnection();

            /**
             * 获得交易代码
             *
             * @return 返回一个UUID, 交易代码，用于标识一次会话过程．
             */
            T transCode();

            /**
             * 会话中的数据内容
             *
             * @return session中的数据类型。
             */
            D getData();

            /**
             * 会话中的数据内容
             *
             * @return session中的数据类型。
             */
            D setData(final D data);

            /**
             * 返回会话属性集合
             *
             * @return 绘画属性
             */
            Map<Object, Object> getAttributes();

            /**
             * 查询结果集合
             *
             * @param sql    preppared sql 语句
             * @param params params sql 语句中占位符参数的值集合，位置从1开始
             * @return 查询结果集合
             * @throws SQLException
             * @throws Exception
             */
            List<IRecord> psql2records(final String sql, final Map<Integer, Object> params) throws SQLException;

            /**
             * 更新数据:execute 与update 同属于与 update
             *
             * @param sql    prepared sql 语句
             * @param params 占位符的对应值的Map,位置从1开始
             * @return 更新结果集合函数有 generatedKeys 键值
             * @throws SQLException
             */
            List<IRecord> psql2update(final String sql, final Map<Integer, Object> params) throws SQLException;

            /**
             * 获得SessionId, 默认采用transCode来实现．
             *
             * @return 返回一个UUID, 交易代码，用于标识一次会话过程．
             */
            default T getSessionId() {
                return transCode();
            }
            
            /**
             * 设置属性
             * @param key 属性的键值
             * @param value 属性的值
             * @return 自身的 IJdbcSession<T,D> 的实例，用以实现链式编程
             */
            default IJdbcSession<T,D> setAttribute(Object key, Object value) {
                this.getAttributes().put(key, value);
                return this;
            }
            
            /**
             * 设置属性
             * @attributes 待设置的属性集合
             * @return 自身的 IJdbcSession<T,D> 的实例，用以实现链式编程
             */
            default IJdbcSession<T,D> setAttributes(Map<Object, Object> attributes) {
                this.getAttributes().putAll(attributes);
                return this;
            }
            
            /**
             * 清空属性集合
             * @return 自身的 IJdbcSession<T,D> 的实例，用以实现链式编程
             */
            default IJdbcSession<T,D> clearAttributes() {
                this.getAttributes().clear();
                return this;
            }
            
            /**
             * 设置属性
             * @param key 属性的键值
             * @return 属性的值，如果不存在返回空
             */
            default Object getAttribute(Object key) {
               return this.getAttributes().get(key);
            }
            
            /**
             * 状态迁移绑定<br>
             * 把 mapper 绑定到当前的 IJdbcSession sess, 进而把sess的当前状态(D) 推进到一个新的状态(X)<br>
             * 注意 :<br>
             * IJdbcSession&lt;T,D&gt;。bind 的实现需要首先检测当前自身的数据状态<br>
             * 对于无效的数据状态 getData()==null 则拒绝执行绑定传递函数:mapper,并返回 null<br>
             * 对于 空值仍旧需要进行bind 的情况 请使用 mapper 函数  返回 Optional.empty() 来代替。 
             * 
             * 借助于 monad 的 可以实现IJdbcSession的级联状态迁移. <br>
             * 例如 :monad(d->x).bind(x->y).bind(y->z) ... 进而 实现 数据状态上的级联。
             * 
             * @param <X>  目标容器的参数类型
             * @param mapper 状态迁移函数: d -> x, 表示从d转换成d1状态，2是to的简写
             * @return 状态为X类型的数据容器:IJdbcSession&lt;T,X&gt;
             * @throws SQLException
             * @throws Exception
             */
            default <X> IJdbcSession<T, X> bind(final FunctionWithException<D, X> mapper)
                    throws SQLException, Exception {

                final var d = this.getData();// 提取monad中的数据
                return d == null ? null : this.fmap(d, mapper);// 这句是关键如果 当前数据为null 则不再做继续传递的操作。
            }
            
            /**
             * 状态迁移绑定<br>
             * 把 mapper 绑定到当前的 IJdbcSession sess, 进而把sess的当前状态(D) 推进到一个新的状态(X)<br>
             * 注意 :<br>
             * IJdbcSession&lt;T,D&gt;。bind 的实现需要首先检测当前自身的数据状态<br>
             * 对于无效的数据状态 getData()==null 则拒绝执行绑定传递函数:mapper,并返回 null<br>
             * 
             * 借助于 monad 的 可以实现IJdbcSession的级联状态迁移. <br>
             * 例如 :monad(d->x).bind(x->y).bind(y->z) ... 进而 实现 数据状态上的级联。
             * 
             * @param <X>  目标容器的参数类型
             * @param mapper 状态迁移函数: d -> x, 表示从d转换成d1状态，2是to的简写
             * @return 状态为X类型的数据容器:Optional&lt;IJdbcSession&lt;T,X&gt;&gt;
             * @throws SQLException
             * @throws Exception
             */
            default <X> Optional<IJdbcSession<T, X>> bindOpt(final FunctionWithException<D, X> mapper)
                    throws SQLException, Exception {
                return Optional.ofNullable(this.bind(mapper));
            }
            
            /**
             * Monad fmap 状态单子 ( fmap 的别名函数 ,强调 IJdbcSession 将作为一个 状态单子出现) <br>
             * 相当于 : fmap(this.getData(), d->x);
             * 
             * @param <X>    目标容器中的元素的类型。
             * @param x 新的状态值
             * @return 状态数据为X类型的IJdbcSession
             * @throws SQLException
             * @throws Exception
             */
            default <X> IJdbcSession<T, X> monad(final X x)
                    throws SQLException, Exception {

                return this.fmap(this.getData(), d->x);
            }
            
            /**
             * Monad fmap 状态单子 ( fmap 的别名函数 ,强调 IJdbcSession 将作为一个 状态单子出现) <br>
             * 相当于 : fmap(this.getData(), mapper);
             * 
             * @param <X>    目标容器中的元素的类型。
             * @param mapper d:当前数据状态->x:目标状态 的 状态迁移函数
             * @return 状态数据为X类型的IJdbcSession
             * @throws SQLException
             * @throws Exception
             */
            default <X> IJdbcSession<T, X> monad(final FunctionWithException<D, X> mapper)
                    throws SQLException, Exception {

                return fmap(this.getData(), mapper);
            }

            /**
             * Monad fmap 状态单子 ( fmap 的别名函数  ,强调 IJdbcSession 将作为一个 状态单子出现)
             * 
             * @param <X>   目标容器中的元素的类型。
             * @param <S>   输入参数的类型:初始入参的类型:Start 开始点入口数据的准备
             * @param start 初始数据 start
             * @param mapper  s->x 的状态迁移函数
             * @return 状态数据为D类型的IJdbcSession
             * @throws SQLException
             * @throws Exception
             */
            default <X, S> IJdbcSession<T, X> monad(final S start, final FunctionWithException<S, X> mapper)
                    throws SQLException, Exception {

                return fmap(start, mapper);
            }
            
            /**
             * Monad fmap 状态单子
             * 
             * @param <X>   目标容器中的元素的类型。
             * @param <S>   输入参数的类型:初始入参的类型:Start 开始点入口数据的准备
             * @param start 初始数据 start
             * @param mapper s->x 的状态迁移函数
             * @return 状态数据为D类型的IJdbcSession
             * @throws SQLException
             * @throws Exception
             */
            default <X, S> IJdbcSession<T, X> fmap(final S start, final FunctionWithException<S, X> mapper)
                    throws SQLException, Exception {
                
                // s2d 是对 new IJdbcSession<T, X>() 中的数据 data 字段的初始化。
                final var outer_data = mapper.apply(start);// 计算映射结果. 然后把这个d 设置到一个新的 IJdbcSession 容器之中.
                final var outer_attributes = new HashMap<>(this.getAttributes());// 会话属性
                final var outer_uuid = this.getSessionId();// 重用当前的 SessionId 以保证Session 共享
                
                // 创建一个新的 IJdbcSession <T,X>
                return new IJdbcSession<>() {// 这就是一个容器的类型的生成过程。注意D是元素类型。IJdbcSession 是容器类型。
                    
                    /**
                     * sqlpattern 的解析 并 对解析后的语句进行 unescape <br>
                     * 
                     * @param sqlpattern sql 模板,可以使是一个shparp变量,比如 :#actIn 这样的语句标号
                     * @return 解析之后的sql
                     */
                    private String sqlparse_unescape(final String sqlpattern) {
                        return MFT(this.sqlparse(sqlpattern, null));
                    }
                    
                    /**
                     * 查询结果集合 <br>
                     */
                    public List<IRecord> psql2records(final String sqlpattern, final Map<Integer, Object> params)
                            throws SQLException {

                        final var pstmt = Jdbc.pstmt(this.getConnection(), SQL_MODE.QUERY, sqlparse_unescape(sqlpattern), params);
                        final var recs = Jdbc.readlines(pstmt.executeQuery(), true); // 查询
                        pstmt.close();// 读取数据并关闭语句

                        return recs;
                    }
                    
                    /**
                     * 更新数据:execute 与update 同属于与 update <br>
                     */
                    public List<IRecord> psql2update(final String sqlpattern, final Map<Integer, Object> params)
                            throws SQLException {
                        
                        final var pstmt = Jdbc.pstmt(this.getConnection(), SQL_MODE.UPDATE, sqlparse_unescape(sqlpattern), params);
                        final var recs = Jdbc.readlines(pstmt.getGeneratedKeys(), true); // 获取生成主键信息，字段名称为：GENERATED_KEY
                        pstmt.close();// 读取数据并关闭语句
                        
                        return recs;
                    }
                    
                    // 创建session 会话
                    @Override
                    public Connection getConnection() {
                        return IJdbcSession.this.getConnection();
                    }
                    
                    @Override
                    public T transCode() {
                        return uuid;
                    }// 交易编码的实现
                    
                    @Override
                    public X getData() {
                        return this.data;
                    }// 会话中的数据

                    @Override
                    public X setData(X data) {
                        return this.data = data;
                    }// 会话中的数据
                    
                    @Override
                    public Map<Object, Object> getAttributes() {
                        return this.attributes;
                    }// 返回会话属性
                    
                    private X data = outer_data; // 计算映射结果
                    private final T uuid = outer_uuid;// 重用当前的 SessionId 以保证Session 共享
                    private final Map<Object, Object> attributes = outer_attributes;// 会话属性,继承前会话属性数据
                };// IJdbcSession
                
            }// fmap

            /**
             * 查询结果并给予归集<br>
             * 执行sql语句查询出结果集合。不会尝试调用spp 进行sql解析
             *
             * @param <U> 归集器结果类型
             * @param sql sql 语句
             * @param collector 归集器 [rec]->u
             * @return U 类型的结果
             * @throws SQLException
             * @throws Exception
             */
            default <U> U sql2u(final String sql, final Collector<IRecord,?, U> collector) throws SQLException, Exception {
                return this.sql2u(sql, REC(), collector);
            }
            
            /**
             * 查询结果并给予归集<br>
             * 注意这里的 rec 是对SQL 中的参数补充，而不是对preparedStatement 中的参数。
             * 
             * @param <U> 归集器结果类型
             * @param sql    sql 语句
             * @param params sql 语句中占位符参数的值集合，位置从1开始
             * @param collector 归集器 [rec]->u
             * @return U 类型的结果
             * @throws SQLException
             * @throws Exception
             */
            default <U> U sql2u(final SQL sql, final IRecord params, final Collector<IRecord,?, U> collector) throws SQLException, Exception{
                return this.sql2records(sql, params).stream().collect(collector);
            }
            
            /**
             * 查询结果并给予归集<br>
             * 使用自身带有的spp(sqlpattern
             * 的解释器,前提需要设置Class<SqlPatternPreprocessor>为键值的属性)执行sql语句查询出结果集合.<br>
             * 比如：传入与sharp标号语句：让spp 从其语句库中检索。<br>
             * final var recs = sess.sql2records("#getCytokines",REC("name",name)); <br>
             * 或者是直接传入带有sharp变量编号(比如下图的“#name”)的语句让spp解析。<br>
             * final var recs = sess.sql2records( <br>
             * "MATCH (n)-[:Secrete]->(b) where b.name=#name RETURN n.name as host",<br>
             * REC("name",name)); <br>
             *
             * @param <U>        归集器结果类型
             * @param sqlpattern sql模板：可以是一个sharp语句标记：比如#getUser,用于从模板文件中提取脚本，也可以是函数有sharp变量的语句模板。
             * @param params     sharp变量的形参与实际参数的对应关系
             * @param collector  归集器 [rec]->u
             * @return U 类型的结果
             * @throws SQLException
             * @throws Exception
             */
            default <U> U sql2u(final String sqlpattern, final IRecord params, final Collector<IRecord, ?, U> collector)
                    throws SQLException, Exception {
                return this.sql2records(sqlpattern, params).stream().collect(collector);
            }
            
            /**
             * 查询结果并给予归集<br>
             * 执行sql语句查询出结果集合.<br>
             * 比如：传入与sharp标号语句：让spp 从其语句库中检索。<br>
             * final var recs = sess.sql2records("#getCytokines",REC("name",name),spp); <br>
             * 或者是直接传入带有sharp变量编号(比如下图的“#name”)的语句让spp解析。<br>
             * final var recs = sess.sql2records( <br>
             * "MATCH (n)-[:Secrete]->(b) where b.name=#name RETURN n.name as host",<br>
             * REC("name",name),spp); <br>
             *
             * @param <U>        归集器结果类型
             * @param sqlpattern sql模板：可以是一个sharp语句标记：比如#getUser,用于从模板文件中提取脚本，也可以是函数有sharp变量的语句模板。
             * @param params     sharp变量的形参与实际参数的对应关系
             * @param spp        sqlpattern 的解释器
             * @param collector  归集器 [rec]->u
             * @return IRecord类型的结果集合
             * @throws SQLException
             * @throws Exception
             */
            default <U> U sql2u(final String sqlpattern, final IRecord params, final SqlPatternPreprocessor spp,
                    final Collector<IRecord, ?, U> collector) throws SQLException, Exception {
                return this.sql2records(spp.handle(null, params, sqlpattern, null)).stream().collect(collector);
            }

            /**
             * 执行sql语句查询出结果集合。不会尝试调用spp 进行sql解析
             *
             * @param sql sql 语句
             * @return IRecord类型的结果集合
             * @throws SQLException,Exception
             */
            default Stream<IRecord> sql2stream(final String sql) throws SQLException, Exception {
                return this.sql2records(sql).stream();
            }
            
            /**
             * 执行sql语句查询出结果集合。不会尝试调用spp 进行sql解析
             *
             * @param sql sql 语句
             * @param params sql 语句中占位符参数的值集合，位置从1开始
             * @return IRecord类型的结果集合
             * @throws SQLException,Exception
             */
            default Stream<IRecord> sql2stream(final String sql,final IRecord params) throws SQLException, Exception {
                return this.sql2records(sql,params).stream();
            }

            /**
             * 执行sql语句查询出结果集合。<br>
             * 一般不会尝试调用spp 进行sql解析,但是 当sql为"#开头的namedsql的时候，会调用spp给予解析") <br>
             * sql2records 的核心函数 <br>
             *
             * @param sql sql 语句
             * @return IRecord类型的结果集合
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> sql2records(final String sql) throws SQLException, Exception {
                var _sql = sql.strip(); // 去除多余的首尾空格
                if(_sql.startsWith("#")) _sql = this.sqlparse(_sql, REC());
                return this.psql2records(_sql, (Map<Integer, Object>) null);
            }

            /**
             * sql2records Extend 增强版的sql2records <br>
             * 使用内置的 SqlPatternPreprocessor(spp) 对 sql 进行预处理<bar> 
             * 比如：<br>
             * jdbc.withTransaction(sess->{ <br>
             * final var recs = sess.sql2records_ex("#getTables"); <br>
             * },Jdbc.M(SqlPatternPreprocessor.class,spp)); <br>
             * <p>
             * 执行sql语句查询出结果集合
             *
             * @param sql sql 语句
             * @return IRecord类型的结果集合
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> sql2records_ex(final String sql) throws SQLException, Exception {
                return this.sql2records(sql, REC());
            }

            /**
             * 注意这里的 rec 是对SQL 中的参数补充，而不是对preparedStatement 中的参数。
             *
             * @param sql    sql 语句
             * @param params sql 语句中占位符参数的值集合，位置从1开始
             * @return IRecord 集合
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> sql2records(final SQL sql, final IRecord params) throws SQLException, Exception {
                return this.psql2records(sql.string(params), params);
            }

            /**
             * 查询结果集合
             *
             * @param sql 命名SQL语句
             * @return 查询结果集合
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> sql2records(final SQL sql) throws SQLException, Exception {
                return this.sql2records(sql, sql.getSqlCtxAsOneRecord());
            }

            /**
             * 使用自身带有的spp(sqlpattern
             * 的解释器,前提需要设置Class<SqlPatternPreprocessor>为键值的属性)执行sql语句查询出结果集合.<br>
             * 比如：传入与sharp标号语句：让spp 从其语句库中检索。<br>
             * final var recs = sess.sql2records("#getCytokines",REC("name",name)); <br>
             * 或者是直接传入带有sharp变量编号(比如下图的“#name”)的语句让spp解析。<br>
             * final var recs = sess.sql2records( <br>
             * "MATCH (n)-[:Secrete]->(b) where b.name=#name RETURN n.name as host",<br>
             * REC("name",name)); <br>
             *
             * @param sqlpattern sql模板：可以是一个sharp语句标记：比如#getUser,用于从模板文件中提取脚本，也可以是函数有sharp变量的语句模板。
             * @param params     sharp变量的形参与实际参数的对应关系
             * @return IRecord类型的结果集合
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> sql2records(final String sqlpattern, final IRecord params)
                    throws SQLException, Exception {
                
                return this.sql2records(this.sqlparse(sqlpattern, params));
            }

            /**
             * 执行sql语句查询出结果集合.<br>
             * 比如：传入与sharp标号语句：让spp 从其语句库中检索。<br>
             * final var recs = sess.sql2records("#getCytokines",REC("name",name),spp); <br>
             * 或者是直接传入带有sharp变量编号(比如下图的“#name”)的语句让spp解析。<br>
             * final var recs = sess.sql2records( <br>
             * "MATCH (n)-[:Secrete]->(b) where b.name=#name RETURN n.name as host",<br>
             * REC("name",name),spp); <br>
             * 
             * <br>
             * 如果没有配置spp,则使用 Term.FT做变量填充,用FT 填充变量的时候不需要 使用sharpPattern,当然也是可以用sharpPattern来标识变量的<br>
             * 前提REC中的变量需要用#开头 <br>
             * 比如:sess.sqlexecute("insert into t_num(num) values(#num)",REC("#num",e)); <br>
             *
             * @param sqlpattern sql模板：可以是一个sharp语句标记：比如#getUser,用于从模板文件中提取脚本，也可以是函数有sharp变量的语句模板。
             * @param params     sharp变量的形参与实际参数的对应关系
             * @param spp        sqlpattern 的解释器
             * @return IRecord类型的结果集合
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> sql2records(final String sqlpattern, final IRecord params, 
                    final SqlPatternPreprocessor spp) throws SQLException, Exception {
                return this.sql2records(this.sqlparse(sqlpattern, params, spp));
            }

            /**
             * 从结果集中提取一行数据。
             *
             * @param <U>         返回值类型
             * @param sql         sql 语句
             * @param targetClass 目标结果类型,当targetClass 为Boolean.class,boolean.class 的时候 返回结果 为null的时候回被 视为 false
             * @return 一条结果的数据集合，单行数据或者没有数据。
             * @throws SQLException
             * @throws Exception
             */
            @SuppressWarnings("unchecked")
            default <U> U sql2get(final String sql, final Class<U> targetClass) throws SQLException, Exception {
                return this.sql2maybe(sql, targetClass)
                        .orElse((Boolean.class.isAssignableFrom(targetClass)|| boolean.class.isAssignableFrom(targetClass))
                              ? (U) (Object) false 
                              : null);
            }

            /**
             * 使用 spp 的 sql2get
             * 使用自身带有的spp(sqlpattern 的解释器,前提需要设置Class<SqlPatternPreprocessor>为键值的属性)执行sql语句查询出结果集合.<br>
             * 比如：传入与sharp标号语句：让spp 从其语句库中检索。<br>
             * final var recs = sess.sql2records("#getCytokines",REC("name",name)); <br>
             * 或者是直接传入带有sharp变量编号(比如下图的“#name”)的语句让spp解析。<br>
             * final var recs = sess.sql2records( <br>
             * "MATCH (n)-[:Secrete]->(b) where b.name=#name RETURN n.name as host",<br>
             * REC("name",name)); <br>
             * 
             * <br>
             * 如果没有配置spp,则使用 Term.FT做变量填充,用FT 填充变量的时候不需要 使用sharpPattern,当然也是可以用sharpPattern来标识变量的<br>
             * 前提REC中的变量需要用#开头 <br>
             * 比如:sess.sqlexecute("insert into t_num(num) values(#num)",REC("#num",e)); <br>
             *
             * @param <U>        返回值类型
             * @param sqlpattern sql模板：可以是一个sharp语句标记：比如#getUser,用于从模板文件中提取脚本，也可以是函数有sharp变量的语句模板。
             * @param params     sharp变量的形参与实际参数的对应关系
             * @return U 类型的结果
             * @throws SQLException
             * @throws Exception
             */
            default <U> U sql2get(final String sqlpattern, final IRecord params, final Class<U> targetClass) throws SQLException, Exception {
                final var sql = this.sqlparse(sqlpattern, params);
                return this.sql2maybe(sql, targetClass).orElse(null);
            }

            /**
             * 从结果集中提取一行数据。
             *
             * @param <U>         返回值类型
             * @param sql         sql 语句
             * @param targetClass 目标结果类型,当targetClass 为Boolean.class,boolean.class 的时候 返回结果 为null的时候回被 视为 false
             * @return 一条结果的数据集合，单行数据或者没有数据。
             * @throws SQLException
             * @throws Exception
             */
            default <U> U sql2get(final SQL sql, final Class<U> targetClass) throws SQLException, Exception {
                return sql2get(sql.string2(), targetClass);
            }

            /**
             * 从结果集中提取一行数据。
             *
             * @param sql sql 语句
             * @return IRecord
             * @throws SQLException
             * @throws Exception
             */
            default IRecord sql2get(final String sql) throws SQLException, Exception {
                return this.sql2maybe(sql, IRecord.class).orElse(null);
            }

            /**
             * 从结果集中提取一行数据。
             *
             * @param sql sql 语句
             * @return 一条结果的数据集合，单行数据或者没有数据。
             * @throws SQLException
             * @throws Exception
             */
            default Optional<IRecord> sql2maybe(final String sql) throws SQLException, Exception {
                return this.sql2records(sql).stream().findFirst();
            }
            
            /**
             * 从结果集中提取一行数据。
             *
             * @param sqlpattern sql 语句模版
             * @param params 被替换数据的 键值对
             * @return 单行数据或者没有数据。
             * @throws SQLException
             * @throws Exception
             */
            default Optional<IRecord> sql2maybe(final String sqlpattern, final IRecord params) throws SQLException, Exception {
                return this.sql2maybe(this.sqlparse(sqlpattern, params));
            }
            
            /**
             * 从结果集中提取一行数据。
             *
             * @param <U>         返回值类型
             * @param sqlpattern  sql 语句模版
             * @param params      被替换数据的 键值对
             * @param targetClass U类型类
             * @return U类型的结果，单行数据或者没有数据。
             * @throws SQLException
             * @throws Exception
             */
            default <U> Optional<U> sql2maybe(final String sqlpattern, final IRecord params, final Class<U> targetClass)
                    throws SQLException, Exception {
                final var sql = this.sqlparse(sqlpattern, params);
                return this.sql2maybe(sql, targetClass);
            }

            /**
             * 从结果集中提取一行数据。
             *
             * @param <U> 返回值类型
             * @param sql sql 语句
             * @param targetClass U类型类
             * @return U类型的结果，单行数据或者没有数据。
             * @throws SQLException
             */
            default <U> Optional<U> sql2maybe(final String sql, final Class<U> targetClass)
                    throws SQLException, Exception {
                return this.sql2records(sql).stream().findFirst().map(e -> e.mutate(targetClass));
            }

            /**
             * 从结果集中提取一行数据。
             *
             * @param <U> 返回值类型
             * @param sql sql 语句
             * @return 一条结果的数据集合，单行数据或者没有数据。
             * @throws SQLException
             * @throws Exception
             */
            default <U> Optional<U> sql2maybe(final SQL sql, final Class<U> targetClass) throws SQLException, Exception {
                return this.sql2records(sql.string2()).stream().findFirst().map(e -> e.mutate(targetClass));
            }

            /**
             * 从结果集中提取一行数据。
             *
             * @param sql sql 语句
             * @param rec sql 语句参数，被替换数据的 键值对
             * @return 单行数据或者没有数据。
             * @throws SQLException
             * @throws Exception
             */
            default Optional<IRecord> sql2maybe(final SQL sql, final IRecord rec) throws SQLException, Exception {
                return this.sql2maybe(sql.string(rec));
            }

            /**
             * 执行sql语句不产生结果集合.<br>
             *
             * @param sql SQL 语句
             * @return 结果是否为一个resultset
             * @throws Exception
             */
            default boolean sqlexecute(final String sql) throws SQLException {
                var _sql = sql.strip(); // 去除多余的首尾空格
                if (_sql.startsWith("#")) _sql = this.sqlparse(_sql, REC());
                return psqlexecute(_sql, (Object[]) null); // 直接执行SQL语句
            }

            /**
             * 执行sql语句不产生结果集合.<br>
             *
             * @param sql SQL 语句
             * @return 结果是否为一个resultset
             * @throws SQLException
             */
            default boolean sqlexecute(final SQL sql) throws SQLException {
                final var sqline = sql.string2();
                return sqlexecute(sqline == null ? sql.toString() : sqline);
            }

            /**
             * 使用自身带有的spp(sqlpattern 的解释器,前提需要设置Class<SqlPatternPreprocessor>为键值的属性)执行sql语句不产生结果集合.<br>
             * 比如：传入与sharp标号语句：让spp 从其语句库中检索。<br>
             * final var recs = sess.sql2records("#getCytokines",REC("name",name)); <br>
             * 或者是直接传入带有sharp变量编号(比如下图的“#name”)的语句让spp解析。<br>
             * final var recs = sess.sql2records( <br>
             * "MATCH (n)-[:Secrete]->(b) where b.name=#name RETURN n.name as host",<br>
             * REC("name",name)); <br>
             * <br>
             * 如果没有配置spp,则使用 Term.FT做变量填充,用FT 填充变量的时候不需要 使用sharpPattern,当然也是可以用sharpPattern来标识变量的<br>
             * 前提REC中的变量需要用#开头 <br>
             * 比如:sess.sqlexecute("insert into t_num(num) values(#num)",REC("#num",e)); <br>
             *
             * @param sqlpattern sql模板：可以是一个sharp语句标记：比如#getUser,用于从模板文件中提取脚本，也可以是函数有sharp变量的语句模板。
             * @param params     sharp变量的形参与实际参数的对应关系
             * @return IRecord类型的结果集合
             * @throws SQLException
             */
            default boolean sqlexecute(final String sqlpattern, final IRecord params) throws SQLException {
                final var spp = (SqlPatternPreprocessor) this.getAttribute(SqlPatternPreprocessor.class);
                final var _sql = this.sqlparse(sqlpattern, params);// 解释sql
                final var sql = spp != null && spp.name().equals("namedsql_processor_escape_brace")
                        ? MFT(_sql) // 把采用了 namedsql_processor_escape_brace 转义的 字符给转义回来
                        : _sql;
                return this.sqlexecute(sql);
            }

            /**
             * 执行sql语句不产生结果集合.<br>
             * 比如：传入与sharp标号语句：让spp 从其语句库中检索。<br>
             * final var recs = sess.sql2records("#getCytokines",REC("name",name),spp); <br>
             * 或者是直接传入带有sharp变量编号(比如下图的“#name”)的语句让spp解析。<br>
             * final var recs = sess.sql2records( <br>
             * "MATCH (n)-[:Secrete]->(b) where b.name=#name RETURN n.name as host",<br>
             * REC("name",name),spp); <br>
             *
             * @param sqlpattern sql模板：可以是一个sharp语句标记：比如#getUser,用于从模板文件中提取脚本，也可以是函数有sharp变量的语句模板。
             * @param params     sharp变量的形参与实际参数的对应关系
             * @param spp        sqlpattern 的解释器：把sqlpattern转换成sql语句。
             * @return 执行的sql语句是否返回了一个结果集合
             * @throws SQLException
             */
            default boolean sqlexecute(final String sqlpattern, final IRecord params, final SqlPatternPreprocessor spp)
                    throws SQLException {
                return this.sqlexecute(this.sqlparse(sqlpattern, params, spp));
            }

            /**
             * sql语句执行等同于 sql2update
             *
             * @param sql SQL语句
             * @return IRecord List
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> sql2execute(final String sql) throws SQLException, Exception {
                return sqlupdate(sql);
            }

            /**
             * sql语句执行
             *
             * @param sql sql 语句
             * @return 带有 生成的主键 GENERATED_KEY的字段记录
             * @throws SQLException
             * @throws Exception
             */
            default Optional<IRecord> sql2execute2maybe(final String sql) throws SQLException, Exception {
                return this.sql2update(sql).stream().findFirst();
            }

            /**
             * sql语句执行
             *
             * @param sql sql 语句
             * @param <U> 目录结果的类型
             * @return 带有：生成的主键 GENERATED_KEY的字段记录
             * @throws SQLException
             * @throws Exception
             */
            default <U> Optional<U> sql2execute2maybe(final String sql, final Class<U> targetClass) throws SQLException, Exception {
                return this.sql2update(sql).stream().findFirst().map(e -> IRecord.rec2obj(e, targetClass));
            }

            /**
             * sql语句执行
             *
             * @param sql，sql 语句模板，参数采用 #xxx 字符串类型, ##xxx 数值类型,或是 ${xxx} 类型  来进行占位,其中
             * @param rec：sql 语句模板：命名参数集合，key->value的键值对
             * @return 带有：生成的主键 GENERATED_KEY的字段记录
             * @throws SQLException
             * @throws Exception
             */
            default Optional<IRecord> sql2execute2maybe(final SQL sql, final IRecord rec) throws SQLException, Exception {
                return this.sql2update(sql.string(rec)).stream().findFirst();
            }

            /**
             * sql语句执行
             *
             * @param sql insert 或 update 语句
             * @return 生成的主键 GENERATED_KEY,如果没有生成 GENERATED_KEY比如update语句，返回空值
             * @throws SQLException
             * @throws Exception
             */
            default Integer sql2execute2int(final String sql) throws SQLException, Exception {
                final Number num = this.sql2execute2num(sql);
                return num == null ? null : num.intValue();
            }

            /**
             * sql语句执行
             *
             * @param sql insert 或 update 语句
             * @return 生成的主键 GENERATED_KEY，如果没有生成 GENERATED_KEY比如update语句，返回空值
             * 对于非mysql 数据库比如不会生成GENERATED_KEY,但杀局插入成功返回-1
             * @throws SQLException
             * @throws Exception
             */
            default Number sql2execute2num(final String sql) throws SQLException, Exception {
                final Optional<IRecord> maybe = this.sql2execute2maybe(sql);
                final Number num = maybe.isPresent() ? maybe.map(e -> {
                    var gk = e.num("GENERATED_KEY");// 尝试提取
                    return gk == null ? -1 : gk;
                }).get() : null;
                return num;
            }

            /**
             * sql语句执行
             *
             * @param sql：sql 语句模板，参数采用 #xxx 字符串类型, ##xxx 数值类型,或是 ${xxx} 类型  来进行占位,其中
             * @param rec：sql 语句模板：命名参数集合，key->value的键值对
             * @return 生成的主键 GENERATED_KEY
             * @throws SQLException
             * @throws Exception
             */
            default int sql2execute2int(final SQL sql, final IRecord rec) throws SQLException, Exception {
                return sql2execute2num(sql, rec).intValue();
            }

            /**
             * sql语句执行
             *
             * @param sql     : sql 语句模板，参数采用 #xxx 字符串类型, ##xxx 数值类型,或是 ${xxx} 类型  来进行占位,其中
             * @param rec：sql 语句模板：命名参数集合，key->value的键值对
             * @return 生成的主键 GENERATED_KEY
             * @throws SQLException
             * @throws Exception
             */
            default Number sql2execute2num(final SQL sql, final IRecord rec) throws SQLException, Exception {
                return sql2execute2num(sql.string(rec));
            }

            /**
             * sql语句执行  这是对sqlupdate的别名
             *
             * @param sql sql 语句
             * @return 查询结果集合
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> sql2update(final String sql) throws SQLException, Exception {
                return this.sqlupdate(sql);
            }

            /**
             * 更新数据:execute 与update 同属于与 update
             *
             * @param sql SQL语句 这里是采用 preparedStatement 来执行。
             * @return sql 语句的执行记过
             * @throws SQLException
             */
            default List<IRecord> sqlupdate(final String sql) throws SQLException {
                return psql2update(sql, (Map<Integer, Object>) null);
            }

            /**
             * 执行sql语句更新
             *
             * @param sql sql 语句
             * @param rec 语句参数
             * @return 返回结果列表
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> sqlupdate(final SQL sql, final IRecord rec) throws SQLException, Exception {
                return this.sqlupdate(sql.string(rec));
            }

            /**
             * 执行sql语句更新
             *
             * @param sql sql 语句
             * @return 返回结果列表
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> sqlupdate(final SQL sql) throws SQLException, Exception {
                return this.sqlupdate(sql, sql.getSqlCtxAsOneRecord());
            }

            /**
             * 批量執行sql语句集合
             *
             * @param sqls sql 语句集合
             * @throws SQLException
             * @throws Exception
             */
            default List<List<IRecord>> sql2batch(final List<String> sqls) throws SQLException, Exception {
                if (sqls == null) return null;
                final List<List<IRecord>> rr = new LinkedList<>();// 语句链表
                for (String sql : sqls) {
                    if (sql == null || sql.length() <= 0 || sql.matches("^[\\s]*$")) continue;
                    rr.add(sql2update(sql));
                }//for
                return rr;
            }

            /**
             * 批量执行目前只能够执行 插入更新语句，而不能自动判断出是 QUERY 还是 UPDATE
             *
             * @param sqls 需要批量执行的语句集合
             * @return 批量执行的结果
             * @throws SQLException
             * @throws Exception
             */
            default List<List<IRecord>> sql2batch(final String... sqls) throws SQLException, Exception {
                return sql2batch(Arrays.asList(sqls));
            }
            
            /**
             * sql语句的模版参数填充
             * <br>
             * 如果没有配置spp,则使用 Term.FT做变量填充,用FT 填充变量的时候不需要 使用sharpPattern,当然也是可以用sharpPattern来标识变量的<br>
             * 前提REC中的变量需要用#开头 <br>
             * 比如:sess.sqlexecute("insert into t_num(num) values(#num)",REC("#num",e)); <br>
             * 
             * @param sqlpattern sql模版
             * @param params     sqlpattern的模版参数
             * @return 使用params填充 sqlpattern 的字符串
             */
            default String sqlparse(final String sqlpattern, final IRecord params) {
                final var spp = (SqlPatternPreprocessor) this.getAttribute(SqlPatternPreprocessor.class);
                return this.sqlparse(sqlpattern, params, spp);
            }

            /**
             * sql语句的模版参数填充
             * <br>
             * 如果没有配置spp,则使用 Term.FT做变量填充,用FT 填充变量的时候不需要 使用sharpPattern,当然也是可以用sharpPattern来标识变量的<br>
             * 前提REC中的变量需要用#开头 <br>
             * 比如:sess.sqlexecute("insert into t_num(num) values(#num)",REC("#num",e)); <br>
             * 
             * @param sqlpattern sql模版
             * @param params     sqlpattern的模版参数
             * @param spp        SqlPatternPreprocesso模版参数 模版的预处理参数
             * @return 使用params填充 sqlpattern 的字符串
             */
            default String sqlparse(final String sqlpattern, final IRecord params, final SqlPatternPreprocessor spp) {
                if (spp == null) {
                    return Term.FT(sqlpattern, params); // 默认使用Term.FT来进行填充
                } else {
                    var _sqlpattern = sqlpattern;// sql语句的模式
                    if (params != null && spp != null && "namedsql_processor_escape_brace".equals(spp.name())) { // 手动完成参数 _sqlpattern 的预处理
                        for (int i = 0; i < params.size(); i++) {
                            final var v = params.get(i);
                            if (v instanceof String) params.set(i, MFT_ESCAPE((String) v));
                        } // for
                        _sqlpattern = MFT_ESCAPE(sqlpattern); // 对 SQL模版进行预处理
                    } // if
                    final var sql = spp.handle(null, params, _sqlpattern, null); // 参数填充,调用spp 进行参数填充的时候需要对_sqlpattern预处理
                    return sql;
                }
            }

            /**
             * 执行SQL语句（直接使用）
             *
             * @param sql prepared sql语句
             * @param oo  prepared sql 语句中的参数的值数组
             * @return 结果是否为一个resultset
             * @throws SQLException
             */
            default boolean psqlexecute(final String sql, final Object[] oo) throws SQLException {
                
                final Map<Integer, Object> params = new LinkedHashMap<>();
                if (oo != null) {// 把数据参数调制成 位置参数Map
                    for (int i = 0; i < oo.length; i++) {
                        params.put(i + 1, oo[i]);// pareparedstatement 占位符 从1开始
                    } // for
                } // if oo!=null
            
                final var pstmt = pstmt(this.getConnection(), SQL_MODE.UPDATE, sql, params);
                try {
                    final var b = pstmt.execute();
                    pstmt.close();// 关闭语句
                    return b;
                } catch (Exception e) {
                    System.err.println("error sql:" + sql);
                    throw e;
                }
            }
            
            /**
             * 查询结果集合
             *
             * @param <U>    归集器结果类型
             * @param sql    preppared sql 语句
             * @param params sql 语句中占位符参数的值集合，位置从1开始
             * @param collector  归集器 [rec]->u
             * @return 查询结果集合
             * @throws SQLException
             * @throws Exception
             */
            default <U> U psql2u(final String sql, final IRecord params, final Collector<IRecord, ?, U> collector)
                    throws SQLException {
                return this.psql2records(sql, params).stream().collect(collector);
            }
            
            /**
             * 查询结果集合
             *
             * @param <X>    参数类型
             * @param <U>    结果类型
             * @param sql    preppared sql 语句
             * @param params sql 语句中占位符参数的值列表，位置从1开始
             * @param collector  归集器 [rec]->u
             * @return 查询结果集合
             * @throws SQLException
             * @throws Exception
             */
            default <X,U> List<IRecord> psql2u(final String sql, final List<X> params,
                    final Collector<IRecord, ?, U> collector) throws SQLException {
                return psql2records(sql, params == null ? new Object[] {} : params.toArray());
            }
            
            /**
             * 查询结果集合
             *
             * @param <U>    结果类型
             * @param sql preppared sql 语句
             * @param oo  preppared sql 语句中占位符参数的值数组
             * @param collector  归集器 [rec]->u
             * @return 查询结果集合
             * @throws SQLException
             * @throws Exception
             */
            default <U> U psql2u(final String sql, final Object[] oo,final Collector<IRecord, ?, U> collector) throws SQLException {
                return psql2records(sql,oo).stream().collect(collector);
            }

            /**
             * 查询结果集合
             *
             * @param sql    preppared sql 语句
             * @param params sql 语句中占位符参数的值集合，位置从1开始
             * @return 查询结果集合
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> psql2records(final String sql, final IRecord params) throws SQLException {
                final var mm = new HashMap<Integer, Object>();
                params.filter(kvp->kvp._1().matches("\\+?\\d+")) // 过滤掉非数字key
                .foreach((k, v) -> {
                    try {
                        final var i = Integer.parseInt(k);
                        mm.put(i, v);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });// foreach
                return psql2records(sql, mm);
            }

            /**
             * 查询结果集合
             *
             * @param <U>    参数类型
             * @param sql    preppared sql 语句
             * @param params sql 语句中占位符参数的值列表，位置从1开始
             * @return 查询结果集合
             * @throws SQLException
             * @throws Exception
             */
            default <U> List<IRecord> psql2records(final String sql, final List<U> params) throws SQLException {
                return psql2records(sql, params == null ? new Object[] {} : params.toArray());
            }

            /**
             * 查询结果集合
             *
             * @param sql preppared sql 语句
             * @param oo  preppared sql 语句中占位符参数的值数组
             * @return 查询结果集合
             * @throws SQLException
             * @throws Exception
             */
            default List<IRecord> psql2records(final String sql, final Object[] oo) throws SQLException {
                final Map<Integer, Object> params = new LinkedHashMap<>();
                if (oo != null) for (int i = 0; i < oo.length; i++) params.put(i + 1, oo[i]);// pareparedstatement 占位符 从1开始
                return psql2records(sql, params);
            }

            /**
             * 查询结果集合
             *
             * @param <U>         返回值的类型
             * @param sql         preppared sql 语句
             * @param params      preppared sql 语句中占位符参数的值集合，位置从1开始
             * @param targetClass 结果的目标雷西给
             * @return U类型的对象
             * @throws SQLException
             */
            default <U> U psql2get(final String sql, final IRecord params, final Class<U> targetClass) throws SQLException {
                return psql2maybe(sql, params).map(e -> IRecord.rec2obj(e, targetClass)).get();
            }

            /**
             * 查询结果集合
             *
             * @param sql    preppared sql 语句
             * @param params preppared sql 语句中占位符参数的值集合，位置从1开始
             * @return 查询结果Optional
             * @throws SQLException
             */
            default Optional<IRecord> psql2maybe(final String sql, final IRecord params) throws SQLException {
                return psql2records(sql, params).stream().findFirst();
            }

            /**
             * 查询结果集合
             *
             * @param sql preppared sql 语句
             * @param oo  preppared sql 语句中占位参数的值数组
             * @return 查询结果集：Optional
             * @throws SQLException
             */
            default Optional<IRecord> psql2maybe(final String sql, final Object[] oo) throws SQLException {
                return psql2records(sql, oo).stream().findFirst();
            }

            /**
             * 查询结果集合
             *
             * @param <U>         返回值的类型
             * @param sql         preppared sql 语句
             * @param oo          preppared sql 语句中占位参数的值数组
             * @param targetClass 结果的目标雷西给
             * @return U类型的对象
             * @throws SQLException
             */
            default <U> U psql2get(final String sql, final Object[] oo, Class<U> targetClass) throws SQLException {

                return psql2maybe(sql, oo).map(e -> IRecord.rec2obj(e, targetClass)).get();
            }

            /**
             * 更新数据:execute 与update 同属于与 update
             *
             * @param sql    sql 语句
             * @param params 占位符的对应值列表
             * @return 更新结果集合函数有 generatedKeys 键值
             * @throws SQLException
             */
            default <U> List<IRecord> psql2update(final String sql, final List<U> params) throws SQLException {
                return this.psql2update(sql, params == null ? new Object[]{} : params.toArray());
            }

            /**
             * 更新数据:execute 与update 同属于与 update
             *
             * @param sql prepared sql 语句
             * @param oo  语句中占位参数的值数组
             * @return 更新结果集合函数有 generatedKeys 键值
             * @throws SQLException
             */
            default List<IRecord> psql2update(final String sql, final Object[] oo) throws SQLException {
                final Map<Integer, Object> mm = new LinkedHashMap<>();
                if (oo != null) for (int i = 0; i < oo.length; i++) mm.put(i + 1, oo[i]);// pareparedstatement 占位符 从1开始
                return this.psql2update(sql, mm);
            }

            /**
             * 更新数据:execute 与update 同属于与 update
             *
             * @param sql sql 语句
             * @param rec sql语句中占位参数的值集合，位置参数从1开始
             * @return 更新结果集合函数有 generatedKeys 键值
             * @throws SQLException
             */
            default List<IRecord> psql2update(final String sql, final IRecord rec) throws SQLException {
                var mm = rec.toMap2(Integer::parseInt);
                return this.psql2update(sql, mm);
            }

            /**
             * Function Table Get <br>
             * 字段内容提取值:返回单条记录 <br>
             * 其实就是这行一条简单 sql 查询：根据主键获取指定的数据记录 <br>
             * MFT("select * from {0} where {1}={2}",table, x,idfld)) <br>
             *
             * @param <X>   源类型
             * @param table 提取表名
             * @param idfld id字段名
             * @return 字段值的提取函数
             */
            default <X> Function<X, IRecord> ftblget(final String table, final String idfld) {
                return FTBLGET(this, table, idfld);
            }

            /**
             * Function Table Get <br>
             * 字段内容提取值:返回多条记录 <br>
             * 其实就是这行一条简单 sql 查询：根据主键获取指定的数据记录 <br>
             * MFT("select * from {0} where {1}={2}",table, x,idfld)) <br>
             *
             * @param <X>   源类型
             * @param table 提取表名
             * @param idfld id字段名
             * @return 字段值的提取函数
             */
            default <X> Function<X, List<IRecord>> ftblgets(final String table, final String idfld) {
                return FTBLGETS(this, table, idfld);
            }
            
            /**
             * 提取 GENERATED_KEY 字段的数据
             *
             * @param <U>    返回结果的元素的类型,mapper 的变换结果类型
             * @param res    sql 的查询结果集合
             * @param mapper 把GENERATED_KEY 字段转换成目标类型。
             * @return GENERATED_KEY 生成的数据列表
             */
            static <U> List<U> gkeys(final List<IRecord> res, Function<Object, U> mapper) {
                return res.stream().map(e -> e.str("GENERATED_KEY")).map(mapper).collect(Collectors.toList());
            }

            /**
             * 生成一个 GENERATED_KEY 字段的数据
             *
             * @param res sql 的查询结果集合
             * @return GENERATED_KEY 生成的数据列表
             */
            static List<Long> ids(final List<IRecord> res) {
                return gkeys(res, e -> Long.parseLong(e + ""));
            }

            /**
             * GENERATED_KEY 字段生成的数据
             *
             * @param res SQL 语句查询出来的额结果集合
             * @return id值，从res中提取一个数值
             */
            static Long id(final List<IRecord> res) {
                return ids(res).stream().findAny().get();
            }

            /**
             * Function Table Get <br>
             * 字段内容提取值: 返回单条记录<br>
             * 其实就是这行一条简单 sql 查询：根据主键获取指定的数据记录 <br>
             * MFT("select * from {0} where {1}={2}",table, x,idfld)) <br>
             *
             * @param <T>   transCode，即SessionId的类型．又叫事务编号
             * @param <D>   Data，Session 中的数据类型。又叫Monad session 的状态数据。
             * @param <X>   结果函数的 参数类型
             * @param sess  会话对象
             * @param table 提取表名
             * @param idfld id字段名
             * @return 字段值的提取函数
             */
            static <T,D,X> Function<X,IRecord> FTBLGET(IJdbcSession<T, D> sess, String table, String idfld){
                return trycatch(x -> sess.sql2get(MFT(
                    x == null
                    ? "select * from {0} where isnull({1})"
                    : "select * from {0} where {1}=''{2}''",
                    table,idfld, x.toString().replace("\\", "\\\\") // 转义"\n"
                ))); // trycatch
            }

            /**
             * Function Table Get <br>
             * 字段内容提取值:返回多条记录<br>
             * 其实就是这行一条简单 sql 查询：根据主键获取指定的数据记录 <br>
             * MFT("select * from {0} where {1}={2}",table, x,idfld)) <br>
             *
             * @param <T>   transCode，即SessionId的类型．又叫事务编号
             * @param <D>   Data，Session 中的数据类型。又叫Monad session 的状态数据。
             * @param <X>   结果函数的 参数类型
             * @param sess  会话对象
             * @param table 提取表名
             * @param idfld id字段名
             * @return 字段值的提取函数
             */
            static <T,D,X> Function<X,List<IRecord>> FTBLGETS(IJdbcSession<T, D> sess, String table, String idfld){
                return trycatch(x -> sess.sql2records(MFT(
                    x == null
                    ? "select * from {0} where isnull({1})"
                    : "select * from {0} where {1}=''{2}''",
                    table,idfld, x.toString().replace("\\", "\\\\") // 转义"\n"
                ))); // trycatch
            }
            
        }// IJdbcSession

        /**
         * IJdbcSession 专门定义了一套jdbc的操作函数。这些函数的操作不会关闭数据库连接。<br>
         * 这里提供一个半成品的IJdbcSession的实现，以方便具体IJdbcSession的具体实现，没必要每次都从零开始 <br>
         * 可以从AbstractJdbcSession开始，<br>
         *
         * @author gbench
         */
        public abstract class AbstractJdbcSession<T,D> implements IJdbcSession<T,D> {
            
            /**
             * 转义字符的转回
             * @param line 字符串
             * @return 转义字符
             */
            private String unescape(final String line) {
                final var _sql = line!=null && (line.indexOf("'{'") >= 0 || line.indexOf("''") >= 0) // 对于含有 brace 转义的语句 给与转回
                        ? MessageFormat.format(line, (Object[]) null)
                        : line;
                return _sql;
            }

            /**
             * 查询结果集合 <br>
             * precords_throws 比 psql2records_throws 效率要高一点
             * 
             * @param sql    含有位置占位符的sql语句
             * @param params 位置参数,{(pos0,value0),(pos1,value1),...}
             * @return IRecord 集合
             * @throws SQLException
             */
            public List<IRecord> psql2records(final String sql, final Map<Integer, Object> params) throws SQLException {
                return Jdbc.this.precords_throws(this.getConnection(), unescape(sql), params);
            }//

            /**
             * 更新数据:execute 与update 同属于与 update系列
             */
            public List<IRecord> psql2update(final String sql, final Map<Integer, Object> params) throws SQLException {
               return Jdbc.this.psql2records_throws(unescape(sql), params, this.getConnection(), false, SQL_MODE.UPDATE, null,Optional.empty());
            }//
        } // AbstractJdbcSession 

        /**
         * 一个DataManipulation代表一个数据操作计划：需要有媒介载体：即Session来给予表达，即DataManipulation <br>
         * 中的符号概念，具体对应在什么物理物理位置．这些信息通常就是一个数据库连接来给予间接表达．<br>
         * <p>
         * DataManipulation 是专门为了数据库的事务性操作来而创建的接口。<br>
         * 可以发出执行异常的 SQL语句,这是专门为了实现SQL事务而构造的结构。<br>
         * DataManipulation 其实就是对Consumer函数的一个模拟，只是由于Consumer的accept不能够抛出异常 <br>
         * DataManipulation 加入了一个可以抛出异常的invoke <br>
         *
         * @param <T> 会话对象 每个数据操作都会存在一个特有的会话对象，以保留数据操作的上下文信息。<br>
         *            则个会话对象需要由事务的创建者来给予提供。
         * @author gbench
         */
        public interface DataManipulation<T>{
            /**
             * 这个函数主要是通过异常 throw Exception 来表示执行失败
             *
             * @param session 数据操作的媒介载体：即交易会话
             * @throws SQLException
             * @throws IndexOutOfBoundsException
             * @throws Exception
             * @throws Throwable
             */
            void invoke(final T session) throws SQLException, IndexOutOfBoundsException, Exception, Throwable;
        }

        /**
         * 请求模式
         */
        public enum SQL_MODE {QUERY, QUERY_SCROLL, UPDATE}

        /**
         * 指定session 执行DataManipulation．:Session 是Monad对象。因此可以进行函数式的状态编程<br>
         * <p>
         * 发起创建一个IJdbcSession对象，并通过IJdbcSession急性数据库操作<br>
         * 事务处理,每一个事务，系统会动态的创建出一个 session 对象（IJdbcSession），这个Session 对象拥有一个UUID类型的对象标识。<br>
         * 在一次事务性的会话IJdbcSession中：共享一个数据库连接，并且出现操作失败（sql操作)，将给予先前的动作回滚．<br>
         * 事务只能对DML语句进行操作，对数据定义类语句DDL无法操作，例如建表、建立索引、建立分区等。<br>
         * 一般采用如下方式调用此函数：<br>
         * jdbc.withTransaction(sess->{session.sql2records("show databases");});<br>
         *
         * @param dm DataManipulation 代表，数据操作的具体过程 dm 的数据如果需要会馆请使用dm所提供的session 来操作数据,通常采用lamba表达式来给予
         *           创建操作过程：sess->{写入你的操作代码}. 需要注意对于withTransaction创建的会话IJdbcSession 是以monad 容器。其初始数据为Object类型
         *           值为null.
         * @return ret返回值boolean值 ,exception： 异常类型,throwable:异常类型,用于动态代理的默认函数，参见Jdbc.newInstance
         */
        public synchronized IRecord withTransaction(final DataManipulation<IJdbcSession<UUID, Object>> dm) {
            return this.withTransaction(dm, (IJdbcSession<UUID, Object>) null, (Map<Object, Object>) null);
        }

        /**
         * 指定session 执行DataManipulation．:Session 是Monad对象。因此可以进行函数式的状态编程<br>
         * <p>
         * 发起创建一个IJdbcSession对象，并通过IJdbcSession急性数据库操作<br>
         * 事务处理,每一个事务，系统会动态的创建出一个 session 对象（IJdbcSession），这个Session 对象拥有一个UUID类型的对象标识。<br>
         * 在一次事务性的会话IJdbcSession中：共享一个数据库连接，并且出现操作失败（sql操作)，将给予先前的动作回滚．<br>
         * 事务只能对DML语句进行操作，对数据定义类语句DDL无法操作，例如建表、建立索引、建立分区等。<br>
         * 一般采用如下方式调用此函数(使用Jdbc.M设置 session属性)：<br>
         * jdbc.withTransaction(sess->{session.sql2records("show databases");},<br>
         * Jdbc.M(SqlPatternPreprocessor.class,spp));<br>
         *
         * @param dm             DataManipulation 代表，数据操作的具体过程 dm 的数据如果需要会馆请使用dm所提供的session 来操作数据,通常采用lamba表达式来给予
         *                       创建操作过程：sess->{写入你的操作代码}. 需要注意对于withTransaction创建的会话IJdbcSession 是以monad 容器。其初始数据为Object类型
         *                       值为null.
         * @param sessAttributes 附加到sess上的属性信息。注入到 sess 上下文中的属性数据{(key,value)}
         * @return ret返回值boolean值 ,exception： 异常类型,throwable:异常类型,用于动态代理的默认函数，参见Jdbc.newInstance
         */
        public synchronized IRecord withTransaction(final DataManipulation<IJdbcSession<UUID, Object>> dm,final Map<Object, Object> sessAttributes) {
            return this.withTransaction(dm, (IJdbcSession<UUID, Object>) null, sessAttributes);
        }

        /**
         * 指定session 执行DataManipulation．:Session 是Monad对象。因此可以进行函数式的状态编程<br>
         * 发起创建一个IJdbcSession对象，并通过IJdbcSession急性数据库操作<br>
         * 事务处理,每一个事务，系统会动态的创建出一个 session 对象，这个Session 对象拥有一个UUID类型的对象标识。<br>
         * 在一次事务性的会话IJdbcSession中：共享一个数据库连接，并且出现操作失败（sql操作)，将给予先前的动作回滚．<br>
         * 事务只能对DML语句进行操作，对数据定义类语句DDL无法操作，例如建表、建立索引、建立分区等。<br>
         *
         * @param dm             数据操作的具体过程 dm 的数据如果需要会馆请使用dm所提供的session 来操作数据
         * @param sess           数据操作所在的会话会话对象,其实就是对一个Connection的包装.需要注意对于withTransaction创建的会话IJdbcSession 是以monad 容器。其初始数据为Object类型
         *                       值为null.
         * @param sessAttributes 附加到sess上的属性信息。注入到 sess 上下文中的属性数据{(key,value)}
         * @return ret返回值boolean值 ,exception： 异常类型,throwable:异常类型,用于动态代理的默认函数，参见Jdbc.newInstance
         */
        public synchronized IRecord withTransaction (final DataManipulation<IJdbcSession<UUID,Object>>  dm,
            final IJdbcSession<UUID,Object> sess, final Map<Object,Object>sessAttributes) {
            
            boolean success= true;// 执行状态，不是成功就是失败，判断标志就是 completed是否爆出异常
            // IJdbcSession 专门定义了一套jdbc的操作函数。这些函数的操作不会关闭数据库连接。
            final Connection conn = this.supplierConn.get();//  自己创建一个数据库连接，这个数据库连接将在整个transaction 进行共享。
            Exception exception = null;// 异常结构
            Throwable throwable = null;// 可抛出性异常的结构
            try {
                if(conn.getAutoCommit()) conn.setAutoCommit(false);// 取消自动提交。
                try {// DM数据操作
                    //给出一个自定义实现
                    final IJdbcSession<UUID,Object> session = sess != null // 判断参数提供的session 是否有效。
                    ? sess // 非空则采用 参数提供的Session 
                    : new AbstractJdbcSession<>() { // 空值则提供一个默认的实现 会话的实现。
                        @Override
                        public Connection getConnection() {
                            return conn;
                        }// 创建session 会话

                        @Override
                        public UUID transCode() {
                            return uuid;
                        }// 交易编码的实现

                        @Override
                        public Object getData() {
                            return data;
                        }

                        ;// 会话中的数据

                        @Override
                        public Object setData(Object _data) {
                            return this.data = _data;
                        }

                        ;// 会话中的数据

                        @Override
                        public Map<Object, Object> getAttributes() {
                            return this.attributes;
                        }

                        ;// 返回会话属性
                        private final UUID uuid = UUID.randomUUID();
                        private Object data = null;// 初始创建Monad中data 初始化为null
                        private final Map<Object, Object> attributes = new HashMap<>();// 会话属性
                    };// IJdbcSession
                    
                    if( sessAttributes!=null && sessAttributes.size()>0 ){ // 设置session 的会话属性
                        session.setAttributes(sessAttributes);// 设置属性
                    }//if 设置session的属性
                    
                    if(dm!=null) dm.invoke(session); // 方法属性调用
                }catch(Throwable e) { // 出现异常则进行回滚
                    success = false; conn.rollback(); throw e;// 把异常抛向外层
                }finally { // try 异常出现则回滚，标记执行失败
                    if( success ) conn.commit();// 未出现异常则提交结果
                    if( conn!=null && !conn.isClosed() ) conn.close();// 关闭连接
                }// try 异常处理
            }catch (Exception e) {
                exception = e;// 记录异常场景
                e.printStackTrace();
            }catch (Throwable e) {
                throwable = e;// 记录异常场景
                e.printStackTrace();
            }finally {
                try{if(conn!=null && !conn.isClosed())conn.close();}catch(Exception e) {e.printStackTrace();};
            }

            return SimpleRecord.REC2("ret",success,"exception",exception,"throwable",throwable);
        };

        /**
         * 執行sql
         *
         * @param <T>     返回结果类型
         * @param handler 數據庫連接处理子
         * @return 返回结果类型T
         */
        public <T> T sqlexecute(final Function<Connection,T> handler) {
            
            return handler.apply(this.getConnection());
        }

        /**
         * 執行sql
         *
         * @param sql   更新操作的sql语句：update,delete,drop 等
         * @param conn  數據庫連接
         * @param close 是否關閉連接
         * @return 执行状态标记  true if the first result is a ResultSet object; false if it is an update count or there are no results
         */
        public boolean psqlexecute(final String sql, final Map<Integer,Object> params,
            final Connection conn,final boolean close) {
            
           PreparedStatement pstmt = null;
            boolean ret=false;
            if(conn==null) {
                System.out.println("数据库连接为null,不予执行语句！");
                return false;
            }
            try {
                pstmt = conn.prepareStatement(sql);
                if(params!=null)for(var key:params.keySet())pstmt.setObject(key,params.get(key));
                ret = pstmt.execute();
                //System.out.println(ret+"------");
            }catch(Exception e) {
                System.out.println("error sql:\n\""+sql+"\"");
                e.printStackTrace();
            }finally {
                try {
                    if(pstmt!=null)pstmt.close();
                    if(close)conn.close();
                }catch(Exception ee) {
                    ee.printStackTrace();
                }
            }
            
            return ret;
        }

        /**
         * 批量執行sql语句集合
         *
         * @param sqls sql 语句集合
         * @param sqls 數據庫連接
         */
        public List<Boolean> sqlbatch(final List<String>sqls) {
            
            if(sqls==null)return null;
            final Connection conn = this.getConnection();
            List<Boolean> bb = sqls.stream()
                .filter(e->e!=null&&e.length()>0&&!e.matches("^[\\s]*$"))// 滤除空语句
                .map(sql->psqlexecute(sql,null,conn,false))
                .collect(Collectors.toList());
            try {conn.close();}catch(Exception e) {e.printStackTrace();}
            
            return bb;
        }

        /**
         * 批量執行sql语句集合
         *
         * @param sqls sql 语句集合
         */
        public List<Boolean> sqlbatch(final String[] sqls) {
            
            if(sqls==null)return null;
            return this.sqlbatch(Arrays.asList(sqls));
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql 查询语句
         * @param qh  結果的處理
         * @return 执行结果集合的 IRecord 列表
         */
        public<T> T psql2apply(final String sql,final Map<Integer,Object>params,
            final SQL_MODE mode, final QueryHandler<T> qh) {
            
            return psql2apply(sql,params,this.getConnection(),true,mode,qh);
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql  查询语句
         * @param conn 數據庫連接
         * @param mode 请求的模式 :查询还是更新
         * @param qh   結果的處理
         * @return 执行结果集合的 IRecord 列表
         */
        public<T> T psql2apply(final String sql, final Map<Integer,Object>params,
            final Connection conn,final SQL_MODE mode,final QueryHandler<T> qh) {
            
            return psql2apply(sql,params,conn,true,mode,qh);
        }

        /**
         * 这个函数是专门为了DataMatrix::new 来进行设计的．
         * var mx = jdbc.psql2apply(sql,params,DataMatrix::new);
         * 生成结构表对象
         *
         * @param sql      sql 语句
         * @param producer 对象构造行数  (oo,hh)->T , oo数据对象矩阵,hh 表头
         * @return
         */
        public<T> T sql2apply(final String sql,final BiFunction<Object[][],List<String>,T> producer) {
            
            return this.psql2apply(sql, null, producer);
        }

        /**
         * 这个函数是专门为了DataMatrix::new 来进行设计的．<br>
         * var mx = jdbc.psql2apply(sql,params,DataMatrix::new); <br>
         * 生成结构表对象
         *
         * @param sql      sql 语句
         * @param producer 对象构造行数  (oo,hh)->T , oo数据对象矩阵,hh 表头
         * @return T 类型的对象
         */
        public<T> T psql2apply(final String sql,final Map<Integer,Object> params,
            final BiFunction<Object[][],List<String>,T> producer) {
            
            T t = null;
            try {
                t = psql2apply_throws(sql,params,producer);
            }catch(Exception e) {
                e.printStackTrace();
            }
            return t;
        }

        /**
         * 返回的结果集：就是一个key值为列名：ColumnLabel <br>
         * 对于 SQL_UPDATE 模式结果会返回会包括，GENERATED_KEY，生成的主键，COLS_CNT，列数，UPDATED_CNT，更新数据行数。<br>
         *
         * @param sql   查询语句
         * @param conn  數據庫連接
         * @param close 是否關閉連接
         * @param qh    結果的處理
         * @return 执行结果集合的 IRecord 列表
         */
        public<T> T psql2apply(final String sql, final Map<Integer,Object>params,
            final Connection conn,final boolean close, final SQL_MODE mode, final QueryHandler<T> qh) {
            
            T ret = null;
            try {
                ret = this.psql2apply_throws(sql,params, conn, close, mode, qh);
            } catch (SQLException e) {
                e.printStackTrace();
            }//try
            return ret;
        }

        /**
         * 生成结构表对象
         *
         * @param <T>      返回结果的类型
         * @param sql      sql 语句
         * @param producer 对象构造行数  (oo,hh)->T , oo数据对象矩阵,hh 表头
         * @return T类型数据对象 由 producer 所生成。
         */
        public<T> T psql2apply_throws(final String sql,final Map<Integer,Object>params,
            final BiFunction<Object[][],List<String>,T> producer) throws SQLException {
            
            return psql2apply_throws(sql,params,(conn, stmt, rs, rsm, n)->{
                rs.last(); Object[][] oo= new Object[rs.getRow()][n]; rs.beforeFirst();
                while(rs.next())for(int j=1;j<=n;j++)oo[rs.getRow()-1][j-1]=rs.getObject(j);
                Function<Integer,String> foo = i->{String s = null;try{s=rsm.getColumnLabel(i);}catch(Exception ignored) {};return s;};
                List<String> hh = Stream.iterate(1,i->i+1).map(foo).limit(n).collect(Collectors.toList());
                return producer.apply(oo,hh);
            });
        }

        /**
         * sql2apply_throws 是对SQL 语句执行的一种抽象 <br>
         * sql2apply_throws 认为对于任何的一次SQL请求包括：<br>
         * sql 语句,sql语句的处理模式(mode),数据库连接(conn)，连接的使用后处理情况(close)，以及对返回结果的后续加工处理(QueryHandler)。<br>
         * <p>
         * 带有异常抛出的 sql2apply <br>
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel <br>
         * 对于 SQL_UPDATE 模式结果会返回会包括，GENERATED_KEY，生成的主键，COLS_CNT，列数，UPDATED_CNT，更新数据行数。<br>
         *
         * @param sql    查询语句
         * @param qh     結果的處理  (conn, stmt, rs, rsm, cols_cnt)->T
         * @param params sql 中的占位符参数
         * @return 执行结果集合的 IRecord 列表
         */
        public<T> T psql2apply_throws(final String sql, final Map<Integer,Object>params,
            final QueryHandler<T> qh) throws SQLException{
            
            return psql2apply_throws(sql,params,this.getConnection(),true,SQL_MODE.QUERY_SCROLL,qh);
        }

        /**
         * psql:prepared SQＬ的别名．<br>
         * psql2apply_throws 是对SQL 语句执行的一种抽象 <br>
         * psql2apply_throws 认为对于任何的一次SQL请求包括：<br>
         * sql 语句,sql语句的处理模式(mode),数据库连接(conn)，连接的使用后处理情况(close)，以及对返回结果的后续加工处理(QueryHandler)。<br>
         * <p>
         * 带有异常抛出的 sql2apply <br>
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel <br>
         * 对于 SQL_UPDATE 模式结果会返回会包括，GENERATED_KEY，生成的主键，COLS_CNT，列数，UPDATED_CNT，更新数据行数。<br>
         *
         * @param sql    查询语句
         * @param params 语句参数
         * @param conn   數據庫連接
         * @param close  是否關閉連接
         * @param qh     結果的處理  (conn, stmt, rs, rsm, cols_cnt)->T
         * @return 执行结果集合的 IRecord 列表
         */
        public<T> T psql2apply_throws(final String sql, final Map<Integer,Object>params,
                final Connection conn, final boolean close, final SQL_MODE mode, final QueryHandler<T> qh) throws SQLException{
            
            PreparedStatement stmt = null;// 查询语句
            ResultSet rs = null;// 结果集对象
            T ret = null;
            final long begTime = System.currentTimeMillis();
            if(conn == null) {System.out.println("數據連接為空(null),不予進行數據查詢");  return null; }

            try {
                int cols_cnt = 0;// 结果集列数量
                int updated_cnt=0; // 更新的行数量
                stmt = pstmt(conn,mode,sql,params); // 创建语句
                if(mode==SQL_MODE.UPDATE) {// SQL update 模式
                    updated_cnt = stmt.executeUpdate();
                    rs = stmt.getGeneratedKeys();// 获取生成主键信息，字段名称为：GENERATED_KEY
                }else if(mode==SQL_MODE.QUERY_SCROLL) {
                    rs = stmt.executeQuery(); // 执行语句
                }else{//默认为SQL query 模式
                    rs = stmt.executeQuery(); // 执行语句
                }//if
                
                final ResultSetMetaData rsm = rs.getMetaData();
                cols_cnt = rsm.getColumnCount();
                ret = qh.handle(conn, stmt, rs, rsm, cols_cnt);
                if( mode==SQL_MODE.UPDATE && ret instanceof List && ((List<?>)ret).size()==1
                        && ((List<?>)ret).get(0) instanceof IRecord ) {
                    ((IRecord)((List<?>)ret).get(0)).add("COLS_CNT",cols_cnt).add("UPDATED_CNT",updated_cnt );
                }//if 返回结果
            }catch(Exception e) {
                System.out.println("\n-------------gbench提醒：出错sql-------------");
                System.out.println(sql);
                System.out.println("--------------------------------------------\n");
                e.printStackTrace();
                throw e;// 把捕获的异常继续跑出去
            }finally {
                try {
                    if(rs!=null)rs.close();
                    if(stmt!=null)stmt.close();
                    if(close && conn!=null)conn.close();
                }catch(Exception e) {
                    e.printStackTrace();
                    throw e; // 把捕获的异常继续跑出去
                }//try 关闭结果集合
            }//try
            
            final long endTime = System.currentTimeMillis();
            if(debug)System.out.println("last for:"+(endTime-begTime)+"ms");
            
            return ret;
        }

        /**
         * p开头的函数：表示prepared sql相关测操作。
         *
         * @param pstmt prepared 语句
         * @param params 语句参数  pos->value, pos 从1开始
         * @param close 执行结束后是否需要关闭 prepared 语句 
         * @return true if the first result is a ResultSet object; false if the first result is an update count or there is no result
         * @throws SQLException
         */
        public boolean pstmt_execute_throws(final PreparedStatement pstmt,
            final Map<Integer, Object> params, final boolean close) throws SQLException {

            if (params != null) for (var i : params.keySet()) pstmt.setObject(i, params.get(i));
            final boolean b = pstmt.execute();
            if (close) pstmt.close();

            return b;
        }

        /**
         * p开头的函数：表示prepared sql相关测操作。
         * preapared 批处理 <br>
         * 
         * @param pstmt prepared 语句
         * @param params 语句参数
         * @param close 执行结束后是否需要关闭 prepared 语句
         * @return true if the first result is a ResultSet object; false if the first result is an update count or there is no result
         * @throws SQLException
         */
        public boolean pstmt_execute_throws(final PreparedStatement pstmt,final Object[] params, final boolean close) 
                throws SQLException {

            if (params != null) for (int i = 0; i < params.length; i++) {
                pstmt.setObject(i + 1, params[i]);
            }
            final var b = pstmt.execute();
            if (close) pstmt.close();

            return b;
        }

        /**
         * p开头的函数：表示prepared sql相关测操作。
         *
         * @param conn   数据据库连接
         * @param sql    SQL语句
         * @param params parepared 的位置参数{pos->value} pos 从1开始
         * @return true if the first result is a ResultSet object; false if the first result is an update count or there is no result
         * @throws SQLException
         */
        public boolean pconn_execute_throws(final Connection conn, final String sql, final Map<Integer, Object> params)
                throws SQLException {

            return pstmt_execute_throws(conn.prepareStatement(sql), params, true);
        }

        /**
         * p开头的函数：表示prepared sql相关测操作。
         *
         * @param conn 数据据库连接
         * @param sql SQL语句
         * @param pp parepared 的位置参数{pos->value}
         * @return true if the first result is a ResultSet object; false if the first result is an update count or there is no result
         * @throws SQLException
         */
        public boolean pconn_execute_throws(final Connection conn, final String sql, final Object... pp)
                throws SQLException {

            if (pp == null) return false;
            final Map<Integer, Object> params = new HashMap<>();
            for (int i = 1; i <= pp.length; i++) params.put(i, pp[i]);

            return pstmt_execute_throws(conn.prepareStatement(sql), params, true);
        }

        /**
         * 执行psql请求 <br>
         * p开头的函数：表示prepared sql相关测操作
         *
         * @param <T>         目标结果类型
         * @param conn        外界提供的数据库连接。
         * @param transformer 把resultset 转变成目标结果类型。
         * @param sql         sql语句模板
         * @param params      模板参数数组
         * @return 目标类型的T对象
         * @throws Throwable 异常原因。使用Throwable的好处是可以很方便的进行二次异常封装（兼容多种异常类型）这样就可以建立起与JDBC SQL异常的最完整偶联机制。
         */
        public <T> T pconn_query_throws(final Connection conn, final FunctionWithThrowable<ResultSet, T> transformer,
                final String sql, final Object[] params) throws Throwable {

            PreparedStatement pstmt = null;
            ResultSet rs = null;
            T t = null;// 目标结果
            try {

                pstmt = conn.prepareStatement(sql);// 制作Prepare 语句。
                var pcnt = -1;// 默认参数非法
                try {// 检查是否可以使用getParameterCount
                    pcnt = pstmt.getParameterMetaData().getParameterCount();// SQL语句可以接收参数的个数。
                } catch (UnsupportedOperationException ignored) {// 操作不支持异常,说明驱动程序尚未实现该功能
                    //  忽略掉异常堆栈打印
                    // ignored.printStackTrace();
                }// try 方法检测

                // 在SQL模板sql填如实际参数params，生成SQL语句
                if (pcnt > 0 && params != null) {

                    for (int i = 0; i < params.length; i++) { // 模板参数遍历。
                        if (i > pcnt) {// 参数设置超过了 PreparedStatement 所能容纳的参数个数。
                            System.err.println( MFT("参数#{2}设置超过了 PreparedStatement 所能容纳的参数个数{3}。参数设置提前终止！\n" +
                                "set-warnnings:pconn_query_throws-sql:{0},params:{1}",
                                sql, Arrays.asList(params), i, pcnt));
                            break;
                        }// i>pcnt

                        if (params[i] != null) try { // 只有当参数param[i]不为空才给予进行模板参数填充。
                            pstmt.setObject(i + 1, params[i]);// 模板参数填充，注意模板参数需要从 1开始。
                        } catch (Exception x) {
                            System.err.println(MFT("set-error:pconn_query_throws-sql:{0},params:{1}", sql, Arrays.asList(params)));
                            throw x;// 一旦出现设置失败，立即异常抛出。因为参数设置师表就表名，该SQL语句执行不了，尽早告知用户程序，给予处理解决，别浪费时间做无用功。
                        }// if params[i]!=null try
                    }//for 模板参数遍历。

                } else if (pcnt < 0) {// 非法数值表明getParameterCount无法获得参数数量

                    for (int i = 0; i < params.length; i++) { // 模板参数遍历。
                        pstmt.setObject(i + 1, params[i]);// 模板参数填充，注意模板参数需要从 1开始。
                    }//for 模板参数遍历。

                }//if pcnt>0 && params!=null

                rs = pstmt.executeQuery();// 执行结果查询
                t = transformer.apply(rs);// 进行目标类型变换。
            } catch (SQLException e) {
                System.out.println("pconn_query_throws,error sql:" + sql);
                throw e;// 抛出异常 原因。
            } finally {
                if (pstmt != null) pstmt.close();
                if (rs != null) rs.close();
            }// try

            // 返回目标结果。
            return t;
        }

        /**
         * 提供一个数据库连接，来执行callbacks函数 <br>
         *
         * @param connection 数据库连接，如果为null,表示自动创建数据库连接。
         * @param callbacks  conn->t 数据库连接 的操作函数，通过数据库连接生产出目标结果对象 T。
         * @return 执行结果集合的 IRecord 列表
         * @throws SQLException
         */
        public <T> T withConnection_throws(final FunctionWithThrowable<Connection, T> callbacks, 
               final Connection connection) throws SQLException {

            final var ar = new AtomicReference<T>(); // 单值容器
            final var need_close = connection == null;// 外部没有提供数据库连接,则使用自创建的数据库连接。此时在使用完毕后，需要给予关闭。否则连接由外部给予关闭。
            final var _conn = connection == null ? this.getConnection() : connection; // 获取数据库连接

            try {
                ar.set(callbacks.apply(_conn));
            } catch (Throwable e) {
                throw new SQLException(e);
            } finally {
                if (need_close) _conn.close();
            }

            return ar.get(); // 从容器中提取运算结果。
        }

        /**
         * 提供一个数据库连接，来执行callbacks函数
         *
         * @param callbacks conn->t 的回调函数
         * @param <T>       回调函数的返回值类型
         * @return 执行结果集合的 IRecord 列表
         */
        public <T> T withConnection(final FunctionWithThrowable<Connection, T> callbacks) {

            T res = null;
            try {
                res = withConnection_throws(callbacks, null);
            } catch (SQLException e) {
                e.printStackTrace();
            } // 自动创建数据库连接

            return res;
        }

        /**
         * prepared Statement 的查询操纵
         *
         * @param sql prepared Statement
         * @param pp  pp 位置参数集合
         * @return 查询结果结合
         */
        public List<IRecord> precords(final String sql, final Object... pp) {
            List<IRecord> ll = null;
            try {
                ll = this.precords_throws(null, sql, pp);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return ll;
        }

        /**
         * prepared Statement 的查询操纵
         *
         * @param sql prepared Statement
         * @param pp  位置参数集合
         * @return 查询结果结合
         */
        public List<IRecord> precords(final Connection connection, final String sql, final Object... pp) {

            List<IRecord> ll = null;
            try {
                ll = this.precords_throws(null, sql, pp);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return ll;
        }
        
        /**
         * p开头的函数：表示prepared sql相关测操作。
         *
         * @param connection 提供的数据库连接，如果为null 则自动创建
         * @param sql        sql语句模板
         * @param params     sql语句参数 数组 ,可以为空表示没有参数，但此时需要sql中没有?问号占位符，即不做参数设置
         * @return 结果集合
         * @throws SQLException
         */
        public List<IRecord> precords_throws(final Connection connection, final String sql, Map<Integer, Object> params)
                throws SQLException {
            final Object[] _params = params == null ? new Object[] {} : params.values().toArray();// preparedSQL的模板参数列表。
            if (params != null) params.forEach((i, d) -> _params[i - 1] = params.get(i));// 矫正 参数位置
            return precords_throws(connection, sql, _params);
        }

        /**
         * p开头的函数：表示prepared sql相关测操作。
         *
         * @param connection 提供的数据库连接，如果为null 则自动创建
         * @param sql        sql语句模板
         * @param params     sql语句参数 数组 ,可以为空表示没有参数，但此时需要sql中没有?问号占位符，即不做参数设置
         * @return 结果集合
         * @throws SQLException
         */
        public List<IRecord> precords_throws(final Connection connection, final String sql, final Object[] params)
                throws SQLException {

            return this.withConnection_throws(conn -> this.pconn_query_throws(conn, rs -> {
                final var recs = new LinkedList<IRecord>();
                final var lbls = labels(rs);
                final int n = lbls.size();// 结果集的列标签(列名）
                while (rs.next()) {
                    final var rec = new LinkedRecord();
                    for (int i = 1; i <= n; i++) rec.set(lbls.get(i), rs.getObject(i));
                    recs.add(rec);
                }
                return recs;
            }, sql, params), connection);// withConnection
        }

        /**
         * p开头的函数：表示prepared sql相关测操作。
         * 专门为了DataMatrix::new 来进行设计的接口
         *
         * @param mxbuilder 数据矩阵的构建器
         * @param sql       SQL语句
         * @param pp        sql 语句的位置参数：占位符对应的实际数值
         * @param <T>       返回结果的类型即数据矩阵的类型 mxbuilder 所生成的数据对象
         * @return T 类型的结果
         */
        public <T> T pmatrix(final BiFunction<Object[][], String[], T> mxbuilder, final String sql, final Object... pp) {

            T t = null;
            try {
                t = this.pmatrix_throws(mxbuilder, sql, pp);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return t;
        }

        /**
         * p开头的函数：表示prepared sql相关测操作。
         * 专门为了DataMatrix::new 来进行设计的接口
         *
         * @param <T>       返回结果的类型即数据矩阵的类型 mxbuilder 所生成的数据对象的类型
         * @param mxbuilder 数据矩阵的构建器
         * @param sql       语句模板
         * @param pp        sql语句的位置参数：占位符对应的实际数值
         * @return 返回结果的类型即数据矩阵的类型 mxbuilder 所生成的数据对象
         * @throws SQLException
         */
        public <T> T pmatrix2(final BiFunction<String[][], String[], T> mxbuilder, final String sql, final Object... pp) {

            T t = null;

            final BiFunction<Object[][], String[], T> _mxbuilder = (ooo, hh) -> mxbuilder.apply(ooo2sss(ooo), hh);
            try {
                t = this.pmatrix_throws(_mxbuilder, sql, pp);
            } catch (Exception e) {
                e.printStackTrace();
            }

            return t;
        }

        /**
         * p开头的函数：表示prepared sql相关测操作。
         * 专门为了DataMatrix::new 来进行设计的接口
         *
         * @param <T>       返回结果的类型即数据矩阵的类型 mxbuilder 所生成的数据对象的类型
         * @param mxbuilder 数据矩阵的构建器
         * @param sql       语句模板
         * @param pp        sql 参数 sql 语句的位置参数：占位符对应的实际数值
         * @return T 类型的结果
         * @throws SQLException
         */
        public <T> T pmatrix_throws(final BiFunction<Object[][], String[], T> mxbuilder,
                                    final String sql, final Object... pp) throws SQLException {

            return this.withConnection(conn -> this.pconn_query_throws(conn, rs -> {
                var recs = new ArrayList<Object[]>();
                var lbls = labels2(rs);
                int n = lbls.length;

                while (rs.next()) {
                    var oo = new Object[n];
                    for (int i = 1; i <= n; i++) oo[i - 1] = rs.getObject(i);
                    recs.add(oo);
                }
                return mxbuilder.apply(recs.toArray(Object[][]::new), lbls);
            }, sql, pp));// withConnection
        }

        /**
         * 大数据检索,
         * 单次获取数据的数据量 30000
         *
         * @param largesql 大数据sql
         * @return record 数据集合
         */
        public List<IRecord> bigdataQuery(final String largesql) {
            return blockquery(largesql, 30000);
        }

        /**
         * 分块数据检索
         *
         * @param sql       大数据的sql语句
         * @param fecthsize 单次获取数据的数据量大小
         * @return record 数据集合
         */
        @SuppressWarnings("unchecked")
        public List<IRecord> blockquery(final String sql, final int fecthsize) {
            
            final Supplier<String> alias = () -> "table" + UUID.randomUUID().toString().replace("-", "");// 表格别名
            final String big_query = "select count(*) cnt from (" + sql + ") " + alias.get();
            final Optional<IRecord> opt = this.sql2maybe(big_query);
            if (!opt.isPresent()) return new LinkedList<>();
            final int cnt = opt.get().i4("cnt");// 首先读取记录条目数
            final int BATCH_SIZE = Math.abs(fecthsize) > 0 ? Math.abs(fecthsize) : 30000;//默认块大小为30000
            final List<String> sub_sqls = new ArrayList<>(10);
            if (cnt > BATCH_SIZE) {// 只有超过BATCH_SIZE才给予分割
                for (int i = 0; i < cnt; i += BATCH_SIZE) {
                    final int start = i;
                    int end = (i + BATCH_SIZE) - 1;//结束标记
                    if (end > cnt) end = cnt;
                    sub_sqls.add("select * from (" + sql + ") " + alias.get() + " limit " + start + "," + BATCH_SIZE);// 定义子任务处理范围批量大小
                }//for
            } else {//没有超过batchsize不予分割
                sub_sqls.add(sql);
            }//if

            if (System.currentTimeMillis() < 0) {// 代码块开启标志
                final List<IRecord> ll = new LinkedList<>();// 结果集列表
                final int n = sub_sqls.size();// 任务数
                final Object aa[] = new Object[n];// 结果集列表
                final Semaphore semaphore = new Semaphore(1 - n);
                final AtomicInteger counter = new AtomicInteger();//计数器
                sub_sqls.forEach(e -> new Thread(() -> {
                    final int i = counter.getAndIncrement();//线程编号,领取一个任务号,然后执行
                    final String stmt = sub_sqls.get(i);// 获得待执行的sql语句
                    Thread.currentThread().setName("#bigquery-" + i);
                    final long begTime = System.currentTimeMillis();
                    System.out.println("sql 语句验证:[" + i + "]" + e.equals(stmt) + "\ne:" + e + "\nstmt:" + stmt + "\n");
                    final List<IRecord> recs = this.sql2records(stmt);
                    if (System.currentTimeMillis() < 0) { // 关闭该条 选择支路
                        synchronized (ll) {
                            ll.addAll(recs);
                        }
                    } else {
                        aa[i] = recs;
                    }

                    long endTime = System.currentTimeMillis();
                    System.out.println("" + Thread.currentThread().getName() + " last for " + (endTime - begTime) + "ms");
                    semaphore.release();
                }).start());
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return ll.size() > 0 ? ll : Stream.of(aa).map(e -> (List<IRecord>) e).flatMap(Collection::stream).collect(Collectors.toList());
            } else {
                return sub_sqls.parallelStream()// 并行各个子任务
                    .flatMap(e -> this.sql2records(e).stream())// 分组获取数据集
                    .collect(Collectors.toList());// 采用jdk的流式实现
            }//if
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql 查询语句
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IColumn<?>> sql2ll(final String sql) {
            return Arrays.asList(sql2cols(sql, this.getConnection(), true));
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql 查询语句
         * @return 执行结果集合的 IRecord 列表
         */
        public IColumn<?>[] sql2cols(final String sql) {
            return sql2cols(sql, this.getConnection(), true);
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql   查询语句
         * @param con   數據庫連接
         * @param close 是否關閉連接
         * @return 执行结果集合的 IRecord 列表
         */
        public IColumn<?>[] sql2cols(final String sql, final Connection con, final boolean close) {

            return psql2apply(sql, null, con, close, SQL_MODE.QUERY, (conn, stmt, rs, rsm, n) -> {
                final Column<?>[] finalcc = new Column<?>[n];// 初始化空間
                try {
                    // 获得列名
                    Function<Integer, KVPair<String, Integer>> colname = (i) -> {
                        String name = null;
                        try {
                            name = rsm.getColumnLabel(i);
                        } catch (Exception ignored) {
                        }
                        return new KVPair<String, Integer>(name, i);
                    };

                    //构造表头
                    Stream.iterate(1, i -> i + 1).limit(n).map(colname)
                            .forEach((kv) -> {
                                Column<?> c = new Column<>(kv.key());
                                finalcc[kv.value() - 1] = c;
                            });

                    //遍歷數據
                    while (rs.next()) {
                        for (int i = 0; i < n; i++) {
                            Object obj = rs.getObject(i + 1);
                            if (finalcc[i].getType() == null && obj != null)
                                finalcc[i].setType(obj.getClass());
                            finalcc[i].addObject(obj);
                        }//for
                    }//while

                } catch (Exception e) {
                    e.printStackTrace();
                }
                return finalcc;
            });
        }

        /**
         * 查询结果集合 <br>
         * 连接使用完后自动关闭
         *
         * @param sql 查询语句
         * @return 单条数据的结果集
         */
        public Optional<IRecord> sql2maybe(final String sql) {
            List<IRecord> recs = this.sql2records(sql);
            if (recs.size() > 1) System.out.println(sql + "\n返回多条(" + recs.size() + ")数据，仅截取第一条返回！");
            return recs.stream().findFirst();
        }

        /**
         * 查询结果集合
         * 连接使用完后自动关闭
         *
         * @param sql 查询语句
         * @return 单条数据的结果集
         */
        public <T> Optional<T> sql2maybe(final String sql, Class<T> tclazz) {
            return sql2maybe(sql).map(e -> IRecord.rec2obj(e, tclazz));
        }

        /**
         * 查询结果集合
         * 连接使用完后自动关闭
         *
         * @param sql    查询语句
         * @param tclazz 目标结果类型
         * @return 单条数据的结果集
         */
        public <T> T sql2get(final String sql, Class<T> tclazz) {
            return sql2maybe(sql).map(e -> IRecord.rec2obj(e, tclazz)).get();
        }

        /**
         * 查询结果集合
         * 连接使用完后自动关闭
         *
         * @param sql  查询语句
         * @param mode sql 模式查询还是更新
         * @return 单条数据的结果集
         */
        public Optional<IRecord> sql2maybe(final String sql, final SQL_MODE mode) {
            List<IRecord> recs = this.sql2records(sql, mode);
            if (recs.size() > 1) System.out.println(sql + "\n返回多条(" + recs.size() + ")数据，仅截取第一条返回！");
            return recs.stream().findFirst();
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel <br>
         * 连接使用完后自动关闭
         *
         * @param sql 查询语句
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> sql2records(final String sql) {
            return this.psql2records(sql, null, this.getConnection(), true, SQL_MODE.QUERY, null, Optional.empty());
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql  查询语句
         * @param mode 结果获取模式:QUERY,UPDATE
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> sql2records(final String sql, final SQL_MODE mode) {
            return this.psql2records(sql, null, this.getConnection(), true, mode, null, Optional.empty());
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel,连接不予关闭
         *
         * @param sql  查询语句
         * @param mode 结果获取模式，QUERY，UPDATE
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> sql2records(final String sql, final Connection conn, final SQL_MODE mode) {
            if (conn == null) return new LinkedList<>();
            return this.psql2records(sql, null, conn, false, mode, null, Optional.empty());
        }
        
        /**
         * 带有异常抛出 的 结果集查询<br>
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel <br>
         * 连接使用完后自动关闭 <br>
         *
         * @param sql 查询语句
         * @return 执行结果集合的 IRecord 列表
         * @throws SQLException
         */
        public List<IRecord> sql2records_throws(final String sql) throws SQLException {
            return this.psql2records_throws(sql, null, this.getConnection(), true, SQL_MODE.QUERY, null,Optional.empty());
        }

        /**
         * 返回经过变换之后的数据记录
         *
         * @param sql    查询语句
         * @param mapper 结果变换函数 IRecord->T
         * @return 执行结果集合的List<T>
         */
        public <T> List<T> sqlmutate(final String sql, final Function<IRecord, T> mapper) {
            return this.psql2records(sql, null, this.getConnection(), true, SQL_MODE.QUERY, null, Optional.empty())
                    .stream().map(mapper).collect(Collectors.toList());
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql      查询语句
         * @param jsn2keys json keys
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> sql2records(final String sql, final Map<String, String[]> jsn2keys) {
            return this.psql2records(sql, null, this.getConnection(), true,
                    SQL_MODE.QUERY, null, Optional.of(jsn2keys));
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql         查询语句
         * @param jsn2keysrec json keys 的键值集合
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> sql2records(final String sql, final IRecord jsn2keysrec) {
            return this.sql2records(sql, null, jsn2keysrec);
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql         查询语句
         * @param jsn2keysrec json keys 的键值集合
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> sql2records(final String sql, final Map<Integer, Object> params, final IRecord jsn2keysrec) {

            final Map<String, String[]> jsn2keys = new HashMap<>();
            jsn2keysrec.stream().forEach(kvp -> {
                Object obj = kvp._2();
                String[] oo = null;
                if (obj instanceof String) {
                    oo = (obj + "").split("[,]+");
                } else if (obj.getClass().isArray()) {
                    try {
                        oo = (String[]) obj;
                    } catch (Exception e) {
                        return;
                    } // 转换异常忽略该项目
                } else {
                    return;// 忽略该项目
                }
                jsn2keys.put(kvp.key(), oo);
            });
            return this.psql2records(sql, params, this.getConnection(), true,
                    SQL_MODE.QUERY, null, Optional.of(jsn2keys));
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql   查询语句
         * @param close 是否關閉連接
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> sql2records(final String sql, final boolean close) {
            return this.psql2records(sql, null, this.getConnection(), close,
                    SQL_MODE.QUERY, null, Optional.empty());
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql 查询语句
         * @param rec prepared statement 的位置参数 integer->value ,integer 从1开始
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> psql2records(String sql, IRecord rec) {
            final Map<Integer, Object> params = new HashMap<>();
            rec.foreach((k, v) -> {// 位置解析
                Integer key = Integer.parseInt(k);
                params.put(key, v);
            });// 数据转换
            return this.psql2records(sql, params, this.getConnection(), true,
                    SQL_MODE.QUERY, null, Optional.empty());
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql 查询语句
         * @param oo  prepared statement 的位置参数 序列
         * @return 执行结果集合的 IRecord 列表
         */
        public Optional<IRecord> psql2maybe(String sql, Object[] oo) {
            return psql2records(sql, oo).stream().findFirst();
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql    查询语句
         * @param params prepared statement 的位置参数 integer->value ,integer 从1开始
         *               参数序号从1开始。1->xxx,2->yyy..
         * @return 执行结果集合的 IRecord 列表
         */
        public Optional<IRecord> psql2maybe(String sql, IRecord params) {
            return psql2records(sql, params).stream().findFirst();
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql    查询语句
         * @param params prepared statement 的位置参数 integer->value ,integer 从1开始
         * @return 执行结果集合的 IRecord 列表
         */
        public Optional<IRecord> psql2maybe(String sql, Map<String, Object> params) {
            return psql2records(sql, REC(params)).stream().findFirst();
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql         查询语句
         * @param params      prepared statement 的位置参数 integer->value ,integer 从1开始
         * @param targetClass 期待的结果类型的class
         * @param <T>         期待的结果类型的
         * @return 执行结果集合的 IRecord 列表
         */
        public <T> Optional<T> psql2maybe(String sql, Map<String, Object> params, Class<T> targetClass) {
            return psql2records(sql, REC(params)).stream().findFirst().map(e -> IRecord.rec2obj(e, targetClass));
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql         查询语句
         * @param oo          prepared statement 的位置参数数组
         * @param targetClass 期待的结果类型的class
         * @param <T>         期待的结果类型的
         * @return 执行结果集合的 IRecord 列表
         */
        public <T> Optional<T> psql2maybe(String sql, Object[] oo, Class<T> targetClass) {
            return psql2records(sql, oo).stream().findFirst().map(e -> IRecord.rec2obj(e, targetClass));
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql 查询语句
         * @param oo  prepared statement 的位置参数 序列
         * @return 执行结果集合的 IRecord 列表
         */
        public <T> T psql2get(String sql, Object[] oo, Class<T> targetClass) {
            return psql2records(sql, oo).stream().findFirst().map(e -> IRecord.rec2obj(e, targetClass)).get();
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql    查询语句
         * @param params prepared statement的位置参数 序列: 参数序号从1开始。1->xxx,2->yyy..
         * @return 执行结果集合的 IRecord 列表
         */
        public <T> T psql2get(String sql, IRecord params, Class<T> targetClass) {
            return psql2records(sql, params).stream().findFirst().map(e -> IRecord.rec2obj(e, targetClass)).get();
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql 查询语句
         * @param oo  参数列表
         * @return 执行结果集合的 IRecord 列表
         */
        public <T> List<IRecord> psql2records(String sql, List<T> oo) {
            return psql2records(sql, oo.toArray());
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql 查询语句
         * @param oo  参数数组
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> psql2records(final String sql, final Object[] oo) {
            final Map<Integer, Object> params = new HashMap<>();
            if (oo != null) for (int i = 0; i < oo.length; i++) params.put(i + 1, oo[i]);
            return this.psql2records(sql, params, this.getConnection(), true,
                    SQL_MODE.QUERY, null, Optional.empty());
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql    查询语句
         * @param params sql中的占位符多对应的实际数据，即占位符参数
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> psql2records(final String sql, final Map<Integer, Object> params) {
            return this.psql2records(sql, params, this.getConnection(), true,
                    SQL_MODE.QUERY, null, Optional.empty());
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql         查询语句
         * @param recSupplier 行记录的生成器 即提供一种自定义的结果集的行实现
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> psql2records(final String sql, final Map<Integer, Object> params,final Supplier<IRecord> recSupplier) {
            return this.psql2records(sql, params, this.getConnection(), true,
                    SQL_MODE.QUERY, recSupplier, Optional.empty());
        }

        /**
         * 返回的结果集：就是一个中以key值为列名：ColumnLabel
         *
         * @param sql         查询语句
         * @param close       是否關閉連接
         * @param recSupplier 行记录的生成器 即提供一种自定义的结果集的行实现
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> psql2records(final String sql, final Map<Integer, Object> params,
                final boolean close, final Supplier<IRecord> recSupplier) {
            return this.psql2records(sql, params, this.getConnection(), close,
                    SQL_MODE.QUERY, recSupplier, Optional.empty());
        }

        /**
         * 返回的结果集(不会返回空值,null,失败也返回长度为0的list）
         *
         * @param sql   查询语句
         * @param conn  數據庫連接
         * @param close 是否關閉連接
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> psql2records(final String sql, final Map<Integer, Object> params,
                final Connection conn, final boolean close) {
            return this.psql2records(sql, params, conn, close, SQL_MODE.QUERY, null, Optional.empty());
        }

        /**
         * 返回的结果集(不会返回空值,null,失败也返回长度为0的list）
         *
         * @param sql   查询语句
         * @param con   數據庫連接
         * @param close 是否關閉連接
         * @param mode  结果获取模式 QUERY or UDATE
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> psql2records(final String sql, final Map<Integer, Object> params, Connection con, boolean close, SQL_MODE mode) {
            return this.psql2records(sql, params, con, close, mode, null, Optional.empty());
        }

        /**
         * 返回的结果集(不会返回空值,null,失败也返回长度为0的list）
         *
         * @param sql         查询语句
         * @param close       是否關閉連接
         * @param recSupplier 行记录的数据格式
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> psql2records(final String sql, final Map<Integer, Object> params, Connection con, boolean close, final Supplier<IRecord> recSupplier) {
            return this.psql2records(sql, params, con, close, SQL_MODE.QUERY, recSupplier, Optional.empty());
        }

        /**
         * 把一个对象数组转换成一个字符串数组。
         *
         * @param ooo 对象二维数据
         * @return 字符串二维数组
         */
        public static String[][] ooo2sss(final Object[][] ooo) {
            final int height = ooo.length;
            final int width = ooo[0].length;
            String[][] sss = new String[height][];
            for (int i = 0; i < height; i++) {
                sss[i] = new String[width];
                for (int j = 0; j < width; j++) sss[i][j] = ooo[i][j] + "";
            }
        
            return sss;
        }
        
        /**
         * 把标签数组调整成长度为n
         * @param n 目标长度
         * @param lbls 标签数组
         * @return 把标签数组调整成长度为n
         */
        public static String[] adjustLabels(final int n ,final String[] lbls) throws SQLException {
            var labels = lbls == null ? new String[] { "" } : lbls;
            final var sz = labels==null?0:labels.length; // labels的长度
            if (sz < n) {
                labels = new String[n];
                for (int i = 0; i < n; i++) {
                    final var j = i / sz; // 循环次数:即周期号
                    final var k = i % sz; // 周期内偏移量
                    labels[i] = j > 0 // 判断周期号是否大于等于1,超过1则自动追加一个周期号的后缀
                            ? lbls[k] + "_" + j // 生成重复键名的后缀
                            : lbls[k]; // 提取键名
                } // for
                return labels;
            } else {
                return labels;
            }
        }

        /**
         * 提取列标签:数组类型的返回结果
         *
         * @param rs 结果集合
         * @return 标签数组
         * @throws SQLException
         */
        public static String[] labels2(final ResultSet rs) throws SQLException {
        
            String[] aa = null;
            if (rs == null) return null;
            final var rsm = rs.getMetaData();
            final var n = rsm.getColumnCount();
            aa = new String[n];
            for (int i = 1; i <= n; i++) aa[i - 1] = rsm.getColumnLabel(i);
        
            return aa;
        }

        /**
         * 提取列标签:key 从1开始
         *
         * @param rs 结果集合
         * @return 标签的值信息(位置从1开始 ） { 位置 ： Integer - > 标签名 ： String }
         */
        public static Map<Integer, String> labels(final ResultSet rs) {
        
            final var mm = new HashMap<Integer, String>();
            try {
                if (rs == null) return mm;
                final var rsm = rs.getMetaData();
                final var n = rsm.getColumnCount();
                for (int i = 1; i <= n; i++) mm.put(i, rsm.getColumnLabel(i));
            } catch (Exception e) {
                e.printStackTrace();
            }
        
            return mm;
        }

        /**
         * 生成sql语句．
         *
         * @param conn   数据库连接
         * @param sql    语句
         * @param params sql 中的占位符参数
         * @return PreparedStatement
         * @throws SQLException
         */
        public static PreparedStatement pudt_stmt(final Connection conn, final String sql,
            final Map<Integer,Object> params) throws SQLException{
            
            return pstmt(conn, SQL_MODE.UPDATE, sql, params);
        }

        /**
         * 生成sql语句．
         *
         * @param conn 数据库连接
         * @param sql  语句
         * @return PreparedStatement
         * @throws SQLException
         */
        public static PreparedStatement pudt_stmt(final Connection conn, final String sql) throws SQLException{
            
            return pstmt(conn, SQL_MODE.UPDATE, sql, null);
        }

        /**
         * 生成sql语句．
         *
         * @param conn   数据库连接
         * @param mode   语句的类型 UPDATE ,QUERY_SCROLL
         * @param sql    语句：含有占位符
         * @param params sql 参数: {Key:Integer-Value:Object},Key  从1开始。
         * @return PreparedStatement
         * @throws SQLException
         */
        public static PreparedStatement pstmt(final Connection conn,final SQL_MODE mode,final String sql,
                final Map<Integer,Object> params) throws SQLException {
            
            PreparedStatement ps = null;
            if (mode == SQL_MODE.UPDATE) {
                ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);// 生成数据主键
            } else if (mode == SQL_MODE.QUERY_SCROLL) {
                ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
            } else {
                ps = conn.prepareStatement(sql);
            }
        
            final var pm = ps.getParameterMetaData();// 参数元数据
            try {
                final var pcnt = pm.getParameterCount(); // paramcnt;
                if (pcnt > 0 && params != null && params.size() > 0) {
                    for (final var paramIndex : params.keySet()) {
                        if (pcnt < paramIndex) continue;// 对于超出sql的参数位置范围的 参数给予舍弃
                        final var value = params.get(paramIndex);
                        ps.setObject(paramIndex, value);// 设置参数
                    } // for
                } // if
            } catch (UnsupportedOperationException e) {
                if (params != null && params.size() > 0) {
                    for (final var paramIndex : params.keySet()) {
                        final var value = params.get(paramIndex);
                        ps.setObject(paramIndex, value);// 设置参数
                    } // for
                } // if
            } // try
        
            return ps;
        }// pstmt

        /**
         * 数据烹饪大师
         *
         * @author gbench
         */
        interface RecordCooker {
            /**
             * 准备一下开始工作
             * 
             * @param n   结果集的列数量
             * @param rs  结果集
             * @param rsm 结果元数据
             */
            void initialize(int n, ResultSet rs, ResultSetMetaData rsm);

            /**
             * 对数据记录进行操作
             * 
             * @param rec 数据记录
             * @return 操作后的数据记录
             * @throws SQLException
             */
            IRecord cook(IRecord rec) throws SQLException;// 开始工作
        }

        /**
         * 带有抛出异常的函数
         *
         * @param <T> 参数类型
         * @param <U> 返回类型
         * @author xuqinghua
         */
        public interface FunctionWithSQLException<T, U> {
            U apply(T t) throws SQLException;
        }

        /**
         * 带有抛出异常的函数
         *
         * @param <T> 参数类型
         * @param <U> 返回类型
         * @author xuqinghua
         */
        public interface FunctionWithThrowable<T, U> {
            U apply(T t) throws Throwable;
        }

        /**
         * 带有抛出异常的函数
         *
         * @param <T> 参数类型
         * @param <U> 返回类型
         * @author xuqinghua
         */
        public interface FunctionWithException<T, U> {
            U apply(T t) throws Exception;
        }

        /**
         * 返回的结果集(不会返回空值,null,失败也返回长度为0的list）
         *
         * @param sql         查询语句
         * @param params      sql语句中的位置参数
         * @param con         數據庫連接
         * @param close       是否關閉連接
         * @param mode        sql语句的执行模式查询还是更新
         * @param recSupplier 行记录的数据格式
         * @param jsncol2keys 把json列按照指定的序列结构给予展开，即一jsn列表换成多列(keys)
         *                    jsncol2keys是一个 {json列名->展开序列keys}的结构的Map
         * @return 执行结果集合的 IRecord 列表
         */
        public List<IRecord> psql2records(final String sql, final Map<Integer, Object> params, final Connection con, boolean close, SQL_MODE mode,
                final Supplier<IRecord> recSupplier, Optional<Map<String, String[]>> jsncol2keys) {
            
            List<IRecord> ll = new LinkedList<>();
            try {
                ll = this.psql2records_throws(sql, params, con, close, mode, recSupplier, jsncol2keys);
            } catch (Exception e) {
                e.printStackTrace();
            }
            
            return ll;
        }
        
        /**
         * 返回的结果集(不会返回空值,null,失败也返回长度为0的list） 该方法依赖于：psql2apply_throws
         * 
         * @param sql          查询语句
         * @param params       语句参数
         * @param con          數據庫連接
         * @param close        是否關閉連接
         * @param mode         sql语句的执行模式查询还是更新
         * @param recSupplier  行记录的数据格式
         * @param _jsncol2keys 把json列按照指定的序列结构给予展开，即一jsn列表换成多列(keys) _jsncol2keys是一个
         *                     {json列名->展开序列keys}的结构的Map : 比如｛product->[id,name,description]｝
         *
         * @return 执行结果集合的 IRecord 列表,返回结果不为null,可以是一个没有数据的List
         */
        public List<IRecord> psql2records_throws(final String sql,final Map<Integer,Object>params,
                final Connection con,final boolean close,final SQL_MODE mode,final Supplier<IRecord> recSupplier,
                Optional<Map<String,String[]>> _jsncol2keys) throws SQLException {
            
            // System.out.println(sql);
            final Optional<Map<String,String[]>> jsncol2keys = (!_jsncol2keys.isPresent()) ? Optional.empty() : _jsncol2keys;//保证jsncol2keys结构非空
            final Optional<Map<String,String[]>> finaljsncol2keys = jsncol2keys==null?Optional.empty():jsncol2keys;
            final IRecord proto = new LinkedRecord(); // 采用原型法进行记录创建
            final IRecord finalProto=proto;// 转换成 final 类型，java的lambda的要求，这个有点恶心，哈哈！
            final Supplier<IRecord> recsup = (null==recSupplier)? finalProto::duplicate :recSupplier;// 构造默认的记录结构生成器

            // 烹饪 数据的方法，老子道德经曰：治大国，若烹小鲜, Json值字段的记录生成器
            final RecordCooker jsnCooker = new RecordCooker(){
                int n; ResultSet rs; ResultSetMetaData rsm; // n:结果集合的列数量;rs:查询的结果集,rsm:结果集合的字段描述
                ArrayList<String> labels = null;// 列的显示名(label),name 是实际名
                ArrayList<String[]> jks = null; // json 值的列名集合:展开字段序列，索引从0开始，0,1,2 依次对应 第一，第二，第三等．
                
                // 把rec(含有复合字段：jsn的多key字段）cook(转换)成 扁平的结构
                FunctionWithSQLException<IRecord,IRecord> lambda_cook = rec->{// 默认为需要 展开 含有 展开列名 即jks不是全部为null,含有json值列名集合
                   for (int i = 0; i < n; i++) {// 逐列添加数据
                       final var label = labels.get(i);// 列名
                       final String[] seqkeys = jks.get(i);// 对应于第i列（从０开始）的json keys,seqkeys表述key的序列，受到scala影响的命名．
                       Object value = rs.getObject(i + 1);// 列值
                       if (seqkeys != null) {// 需要对jsn字段给予展开,剪开的键名序列不为空
                           if (value == null) value = "{}";// 空对象，保证value有效
                           @SuppressWarnings("unchecked")
                           Map<String, Object> jsnmap = Json.json2obj(value, Map.class);// json 展开成关联数组 Map
                           if (jsnmap == null) {// 默认值的字段填充
                               jsnmap = new HashMap<>();
                               for (var key : seqkeys)rec.add(key, null);//为了保证key名称存在，不过对于Map结构的rec，这是无效的．
                           } // if jsnmap==null
                           // 提取jsnmap中的seqkeys中的键名数据，并把他们置如结果记录里面去．
                           new LinkedRecord(seqkeys, jsnmap).forEach(rec::add);
                       } else {// 不需要对jsn列进行展开
                           rec.add(label, value);
                       } // if 逐列添加数据
                   } /*for*/
                   return rec;
                }; // lambda_cook
                
                // n:结果集合的列数量;rs:查询的结果集,rsm:结果集合的字段描述
                public void initialize(int n, ResultSet rs, ResultSetMetaData rsm) {
                    this.n = n;this.rs = rs;this.rsm = rsm;
                    labels = new ArrayList<>(n);// 便签集合
                    jks = new ArrayList<>(n);// json key 集合
                    for (int i = 0; i < n; i++) {
                        String label = null;
                        try {label = this.rsm.getColumnLabel(i + 1);}catch(Exception ignored) {}
                        labels.add(label);
                        String[] cc = finaljsncol2keys.isPresent() ? finaljsncol2keys.get().get(label) : null;//展开json中的复合列
                        jks.add((cc != null && cc.length > 0) ? cc : null); // 展开键值序列：cc就是展开之后扁平列名集合
                    } // for i
                    // 根据是否含有json字段判断是否开启
                    if(finaljsncol2keys.isEmpty())lambda_cook= rec->
                        {for(int i=0;i<n;i++)rec.add(labels.get(i),rs.getObject(i+1));return rec;};
                }// initialize
                
               // 把rec(含有复合字段：jsn的多key字段）cook(转换成)扁平的结构
                public IRecord cook(IRecord rec) throws SQLException {// 数据烹饪方法：把一个空白记录，赋予内容
                    return lambda_cook.apply(rec);
                };//cooklambda_cook
            };//jsnCooker

            // 简单记录生成器:这个记录生成器已经随着JsonCooker lamba_cook变得意义不大了．但我还是用他，因为简单．
            final RecordCooker simpleCooker = new RecordCooker() {
                int n; ResultSet rs; ResultSetMetaData rsm;
                public void initialize(int n, ResultSet rs, ResultSetMetaData rsm) {// cooker 的基本准备
                    this.n = n;this.rs = rs;this.rsm = rsm;}
                public IRecord cook(IRecord rec) throws SQLException {// 数据烹饪方法：把一个空白记录，赋予内容
                    for (int i = 0; i < n; i++) {rec.add(rsm.getColumnLabel(i + 1), rs.getObject(i + 1));}
                    return rec;
                }//cook
            };//simpleCooker

            final RecordCooker cooker = jsncol2keys.isPresent()?jsnCooker:simpleCooker;//选择一个合适的厨师
            //final RecordCooker cooker = jsnCooker;
            
            // 代码在这里才是真正的开始，以上都是准备工作．准备活动要有条不紊，可以慢（此处的慢是缜密与完备）但不能乱．行动之时要快如闪电．
            final List<IRecord> ll = psql2apply_throws(sql,params,con,close,mode,(conn,stmt,rs,rsm,n)->{ //结果集合的生成．
                final var recs = new LinkedList<IRecord>();
                cooker.initialize(n,rs, rsm);//在烹饪之前准备一下，cooker  准备．．．，Ｇo! Go!! Go!!!
                while(rs.next())recs.add(cooker.cook(recsup.get()));//數據遍历,把rec煮熟一下再放入结果集recs中
                return recs;
            });// sqlquery 查詢結果集

            return ll == null ? new LinkedList<>() : ll;// 返回结果不为null
        }

        protected Supplier<Connection> supplierConn = null;// 数据连接贩卖商
        public static boolean debug = false;// 调试标记
    }

    /**
     * 二元组(t,u)
     * 
     * @author gbench
     *
     * @param <T> 1号位置元素类型
     * @param <U> 2号位置元素类型
     */
    public static class Tuple2<T,U> implements Serializable{

        /**
         * 默认构造函数
         */
        public Tuple2() {
        }

        /**
         * 构造函数
         * 
         * @param t 1号位置的元素
         * @param u 2号位置的严肃
         */
        public Tuple2(final T t, final U u) {
            this._1 = t;
            this._2 = u;
        }

        /**
         * 1号位置的元素值
         * 
         * @return 1号位置的元素值
         */
        public T _1() {
            return _1;
        }

        /**
         * 对 1号位置进行变换
         *
         * @param <V>    返回值的类型 也就是mapper 的结果类型
         * @param mapper 映射函数 t->v
         * @return V 类型的数据
         */
        public <V> V _1(final Function<T, V> mapper) {
            return mapper.apply(_1);
        }

        /**
         * 把1号位置强制类型转换为V类型
         *
         * @param <V>    目标结果类型
         * @param vclass 结果类型
         * @return V类型的结果
         */
        @SuppressWarnings("unchecked")
        public <V> V _1(final Class<V> vclass) {
            return (V) this._1;
        }

        /**
         * 设置1号位置的元素的值
         *
         * @param t 待设置的值
         * @return 设置后的值
         */
        public T _1(final T t) {
            return _1 = t;
        }

        /**
         * 2号位置的元素值
         *
         * @return 2号位置的元素值
         */
        public U _2() {
            return _2;
        }

        /**
         * 使用mapper 对值类型进行变换
         *
         * @param <V>    目标结果类型
         * @param mapper u->v
         * @return V类型的结果
         */
        public <V> V _2(Function<U, V> mapper) {
            return mapper.apply(_2);
        }

        /**
         * 把2号位置强制类型转换为V类型
         *
         * @param <V>    目标结果类型
         * @param vclass 结果类型
         * @return V类型的结果
         */
        @SuppressWarnings("unchecked")
        public <V> V _2(final Class<V> vclass) {
            return (V) this._2;
        }

        /**
         * 设置2号位置的元素的值
         *
         * @param u 待设置的值
         * @return 设置后的值
         */
        public U _2(final U u) {
            return _2 = u;
        }

        /**
         * 交换1号与2号位置 (t,u)->(u,t)  <br>
         *
         * @return (u, t)
         */
        public Tuple2<U, T> swap() {
            return TUP2(this._2, this._1);
        }

        /**
         * Functor 函数
         *
         * @param <X>    目标结果第一位置 类型
         * @param <Y>    目标结果第二位置 类型
         * @param mapper 变换函数 (t,u)->(x,y)
         * @return (x, y)二元组
         */
        public <X, Y> Tuple2<X, Y> fmap(final Function<Tuple2<T, U>, Tuple2<X, Y>> mapper) {
            return mapper.apply(this);
        }

        /**
         * 使用指定变换函数 去 变换各个位置上的 元素内容，并生成一个新的 对象
         *
         * @param <X> 结果的1号 位置类型
         * @param <Y> 结果的2号位置类型
         * @param t2x 1号位置的变换函数
         * @param u2y 2号位置的变换函数
         * @return TUP2(X, Y) 类型的对象。
         */
        public <X, Y> Tuple2<X, Y> fmap(final Function<T, X> t2x, final Function<U, Y> u2y) {
            return TUP2(t2x.apply(_1), u2y.apply(_2));
        }

        /**
         * 使用指定变换函数 去 变换各个位置上的 元素内容，并生成一个新的 对象
         *
         * @param <X> 结果的1号 位置类型
         * @param t2x 1号位置的变换函数
         * @return TUP2(X, U) 类型的对象。
         */
        public <X> Tuple2<X, U> fmap1(final Function<T, X> t2x) {
            return TUP2(t2x.apply(_1), _2);
        }

        /**
         * 使用指定变换函数 去 变换各个位置上的 元素内容，并生成一个新的 对象
         *
         * @param <Y> 结果的2号位置类型
         * @param u2y 2号位置的变换函数
         * @return TUP2(T, Y) 类型的对象。
         */
        public <Y> Tuple2<T, Y> fmap2(final Function<U, Y> u2y) {
            return TUP2(_1, u2y.apply(_2));
        }

        /**
         * 批量设置1号位置
         *
         * @param <V> 1号位置元素
         * @param vv  1号位置元素集合
         * @return {(v,u)}
         */
        public <V> List<Tuple2<V, U>> multiSet1(Collection<V> vv) {
            return zip(vv, Collections.singletonList(this._2), true);
        }

        /**
         * 批量设置1号位置
         *
         * @param <V> 1号位置元素
         * @param vv  1号位置元素集合
         * @return {(v,u)}
         */
        public <V> List<Tuple2<V, U>> multiSet1(final V[] vv) {
            return zip(Arrays.asList(vv), Collections.singletonList(this._2), true);
        }

        /**
         * 批量设置2号位置
         *
         * @param <V> 二号位置元素
         * @param vv  二号位置元素集合
         * @return {(t,v)}
         */
        public <V> List<Tuple2<T, V>> multiSet2(final Collection<V> vv) {
            return zip(Collections.singletonList(this._1), vv, true);
        }

        /**
         * 批量设置2号位置
         *
         * @param <V> 二号位置元素
         * @param vv  二号位置元素集合
         * @return {(t,v)}
         */
        public <V> List<Tuple2<T, V>> multiSet2(final V[] vv) {
            return zip(Collections.singletonList(this._1), Arrays.asList(vv), true);
        }

        /**
         * TUP2(2,1).cons(3) <br>
         * 对 2,1,追加一个 新元素 形成 3-->(2-->1)   <br>
         * 模仿 LISP的cons函数 用v来做新的链表的表头  <br>
         *
         * @param <V> 新追加的元素的类型
         * @param v   新追加的元素
         * @return 0-->(1-->2)
         */
        public <V> Tuple2<V, Tuple2<T, U>> cons(final V v) {
            return TUP2(v, TUP2(this._1, this._2));
        }

        /**
         * 对 1-->2,追加一个 新元素 形成 1-->(2-->3)  <br>
         * 需要注意当：U为Tuple2结构的 结果可会造成 非预期之感觉:  <br>
         * (1,2).append(3).append(4) 的结果是：(1,((2,3),4)), 当 flatMap的时候，会出现 1,4,2,3  <br>
         *
         * @param <V> 新追加的元素的类型
         * @param v   新追加的元素
         * @return 1-->(2-->3)
         */
        public <V> Tuple2<T, Tuple2<U, V>> append(final V v) {
            return TUP2(this._1, TUP2(this._2, v));
        }

        /**
         * 强制转换成T类型的数组元素 把1号二号元素封装成T类型的列表
         *
         * @return T类型的列表元素[t, u], 1号元素对应list的第0个元素，2号元素对应list的第1个元素，列表元素可能包含空元素，代表这一条边(把元组视为边)没有后继或是前驱元素。
         */
        @SuppressWarnings({"unchecked"})
        public List<T> tt() {
            return Arrays.asList((T) this._1, (T) this._2);
        }

        /**
         * 把1号二号元素封装成Object类型的列表
         *
         * @return Object的列表元素[t, u], 1号元素对应list的第0个元素，2号元素对应list的第1个元素，
         */
        public List<Object> oo() {
            return Arrays.asList(this._1, this._2);
        }

        /**
         * 把1号二号元素封装成Object类型的数组
         *
         * @return Object类型的数组:[t,u],1号元素对应list的第0个元素，2号元素对应list的第1个元素，
         */
        public Object[] toArray() {
            return this.toArray(Object[]::new);
        }

        /**
         * 把1号二号元素封装成X类型的数组
         *
         * @param <X>       数组的元素类型
         * @param generator 数组生成器
         * @return X类型的数组:[t,u],1号元素对应list的第0个元素，2号元素对应list的第1个元素，
         */
        public <X> X[] toArray(final IntFunction<X[]> generator) {
            return Arrays.asList(this._1, this._2).toArray(generator);
        }

        /**
         * 把1号二号元素封装成Object类型的流
         *
         * @return Object类型的流:[t,u],1号元素对应list的第0个元素，2号元素对应list的第1个元素，
         */
        public Stream<Object> stream() {
            return Stream.of(this._1, this._2);
        }

        /**
         * 把1号二号元素封装成X类型的流
         *
         * @param <X>   元素类型
         * @param clazz 元素类型类型
         * @return X类型的流:[t,u],1号元素对应list的第0个元素，2号元素对应list的第1个元素，
         */
        @SuppressWarnings("unchecked")
        public <X> Stream<X> stream(final Class<X> clazz) {
            return Arrays.stream(this.toArray(n -> (X[]) Array.newInstance(clazz, 2)));
        }

        /**
         * 把一个二元组转换成一个 目标类型
         *
         * @param <O>    目标类型
         * @param mapper 二元组转换器器(t,u)->o
         * @return O 类型的结果
         */
        public <O> O map(final BiFunction<T, U, O> mapper) {
            return mapper.apply(this._1, this._2);
        }

        /**
         * 对列表的元素进行平铺展开,用于  Tuple2中俄元素类型为 也是Tuple2类型的时候有用。<br>
         * 比如:<br>
         * TUP2(TUP2(1,2),TUP2(3,4)).flatMap(e->e) 将 返回:[3, 4, 1, 2]
         * 即 对于 非 Tuple2元素 按照 _1,_2的顺序 而 Tuple2类型的元素按照 _1,_2 的顺序（实现<br>
         * 采用了堆栈进行层次递进)。进行按展开. <br>
         *
         * @param mapper 结果变换函数:对 _1,_2的值进行变换的函数。
         * @return 0-->(1-->2)
         */
        public <V> List<V> flatMap(final Function<Object, V> mapper) {
            final var tt = new LinkedList<V>();
            final var stack = new Stack<Tuple2<?, ?>>();

            stack.push(this);
            while (!stack.empty()) {
                final var tup = stack.pop();
                Stream.of(tup._1, tup._2).forEach(e -> {
                    if (e instanceof Tuple2) {
                        stack.push((Tuple2<?, ?>) e);
                    } else {
                        tt.add(mapper.apply(e));
                    }//if
                });
            }// while

            return tt;
        }

        /**
         * 使用自身作为1位元素进行 zip
         *
         * @param <V> 新2号位置的元素的类型
         * @param vv  新2号位置元素
         * @return {((T,U),V)} 结构的数组
         */
        public <V> List<Tuple2<Tuple2<T, U>, V>> lzip(final Collection<V> vv) {
            return zip(Collections.singletonList(this), vv, true);
        }

        /**
         * 2号位zip 使用自身作为1位元素进行 zip
         *
         * @param <V> 新2号位置的元素的类型
         * @param vv  新2号位置元素
         * @return {(T,(U,V))} 结构的数组
         */
        public <V> List<Tuple2<T, Tuple2<U, V>>> lzip0(final Collection<V> vv) {
            final var aa = zip(Collections.singletonList(this._2), vv, true);
            return zip(Collections.singletonList(this._1), aa, true);
        }

        /**
         * 使用自身作为2位元素进行 zip
         *
         * @param <V> 新1位的元素的类型
         * @param vv  新1位元素集合
         * @return {(V,(T,U))} 结构的数组
         */
        public <V> List<Tuple2<V, Tuple2<T, U>>> rzip(final Collection<V> vv) {
            return zip(vv, Collections.singletonList(this), true);
        }

        /**
         * 2号位zip 使用自身作为1位元素进行 zip
         *
         * @param <V> 新2号位置的元素的类型
         * @param vv  新2号位置元素
         * @return {(U,(T,V)} 结构的数组
         */
        public <V> List<Tuple2<U, Tuple2<T, V>>> rzip0(final Collection<V> vv) {
            final var m = this.swap().lzip0(vv);
            return m;
        }

        /**
         * hashCode
         * @return hashCode
         */
        public int hashCode() {
            return _1 == null ? Integer.valueOf(0).hashCode() : this._1().hashCode();
        }

        /**
         * @param obj 数据对象
         * @return 判断两个对象相等
         */
        public boolean equals(final Object obj) {
            if (obj instanceof Tuple2) {// 同类比较
                final var tup2 = (Tuple2<?, ?>) obj;
                if (_1 == null && tup2._1 == null) {
                    return _2 == null && tup2._2 == null;
                }
                if (_1 == null)
                    return false;
                if (_2 == null)
                    return false;
                return _1.equals(tup2._1) && _2.equals(tup2._2);
            }
            return _1 != null && _1().equals(obj);
        }

        /**
         * 格式化输出
         * @return 格式化输出
         */
        public String toString() {
            return _1() + " --> " + _2();
        }

        /**
         * 创建一个二元组
         * 
         * @param <M> 1号位置的元素类型
         * @param <N> 2号位置的元素类型
         * @param m   1号位置的元素的值
         * @param n   2号位置的元素的值
         * @return (m,n) 的二元组
         */
        public static <M, N> Tuple2<M, N> TUP2(final M m, final N n) {
            return new Tuple2<>(m, n);
        }

        /**
         * 创建一个二元组
         *
         * @param <T> 元素类型
         * @param tt 键值序列
         * @return 元组(tt[0], tt[1])
         */
        public static <T> Tuple2<T, T> TUP2(final T[] tt) {
            if (tt == null || tt.length < 1) return null;
            final var n = tt.length;
            return TUP2(tt[0 % n], tt[1 % n]);
        }

        /**
         * 把一个字符串str,视作一个由separator分隔出来的列表。把第一项提取在tuple第一项,其余放在tuple第二项 比如 abc/efg/hij
         * 分解成 abc --> efg/hij
         * 
         * @param str       检测的字符串
         * @param separator 分割符号
         * @return
         */
        public static Tuple2<String, String> TUPLE2(final String str, final String separator) {
            int p = str.indexOf(separator);
            Tuple2<String, String> tup = new Tuple2<>();
            if (p < 0) {
                tup._1(str);
            } else {
                tup._1(str.substring(0, p));
                if (p + 1 < str.length())
                    tup._2(str.substring(p + 1));
            } // if
            return tup;
        }

        /**
         * 拼接成一个键值对(默认循环补位）
         *
         * @param <K>     1号位置元素类型
         * @param <V>     2号位置元素类型
         * @param kk      1号位置元素集合
         * @param vv      2号位置元素结合
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> List<Tuple2<K, V>> zip(final Collection<K> kk, final Collection<V> vv){
            return zip(kk,vv,true);
        }

        /**
         * 拼接成一个键值对
         * 
         * @param <K>     1号位置元素类型
         * @param <V>     2号位置元素类型
         * @param kk      1号位置元素集合
         * @param vv      2号位置元素结合
         * @param recycle 是否进行循环补位
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> List<Tuple2<K, V>> zip(final Collection<K> kk, final Collection<V> vv, final boolean recycle) {
            final var tups = new LinkedList<Tuple2<K, V>>();
            final var kitr = kk.iterator();
            final var vitr = vv.iterator();
            K pre_k = null;
            V pre_v = null;
            final var k_size = kk.size();
            final var v_size = vv.size();
            int i=0;// 统计计数
            while (kitr.hasNext() || vitr.hasNext()) {
                var k = kitr.hasNext() ? kitr.next() : null;
                var v = vitr.hasNext() ? vitr.next() : null;
                if (recycle && k == null) {
                    k = pre_k;
                    k = tups.get(i%k_size)._1();// 覆盖掉pre_k的值，这是为了去除pre_k unused的警告
                }
                if (recycle && v == null) {
                    v = pre_v;
                    v = tups.get(i%v_size)._2();// 覆盖掉pre_v的值，这是为了去除pre_v unused的警告
                }
                tups.add(TUP2(k, v));
                pre_k = k;
                pre_v = v;
                i++;
            } // while

            return tups;
        }

        /**
         * 拼接成一个键值对
         * 
         * @param <K>     1号位置元素类型
         * @param <V>     2号位置元素类型
         * @param kk      1号位置元素集合数组
         * @param vv      2号位置元素结合数组
         * @param recycle 是否进行循环补位
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> List<Tuple2<K, V>> zip(final K[] kk, final V[] vv, final boolean recycle) {
            return zip(Arrays.asList(kk), Arrays.asList(vv), recycle);
        }

        /**
         * 拼接成一个键值对
         * 
         * @param <K>     1号位置元素类型
         * @param <V>     2号位置元素类型
         * @param <U>     返回的结果类型
         * @param kk      1号位置元素集合数组
         * @param vv      2号位置元素结合数组
         * @param recycle 是否进行循环补位
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V, U> U zip(final K[] kk, final V[] vv, final boolean recycle, U identity,
                final BiFunction<U, Tuple2<K, V>, U> accumulator, BinaryOperator<U> combiner) {
            return zip(Arrays.asList(kk), Arrays.asList(vv), recycle).stream().reduce(identity, accumulator, combiner);
        }

        /**
         * 拼接成一个键值对
         * 
         * @param <K> 1号位置元素类型
         * @param <V> 2号位置元素类型
         * @param <U> 返回的结果类型
         * @param kk  1号位置元素集合数组
         * @param vv  2号位置元素结合数组
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V, U> U zip(final Collection<K> kk, final Collection<V> vv, final boolean recycle, U identity,
                final BiFunction<U, Tuple2<K, V>, U> accumulator, BinaryOperator<U> combiner) {
            return zip(kk, vv, recycle).stream().reduce(identity, accumulator, combiner);
        }

        /**
         * 拼接成一个键值对 recycle 默认循环补位
         * 
         * @param <K>         1号位置元素类型
         * @param <V>         2号位置元素类型
         * @param <U>         返回的结果类型
         * @param kk          1号位置元素集合数组
         * @param vv          2号位置元素结合数组
         * @param identity    起始点
         * @param accumulator 累加器
         * @param combiner    中间值合并器
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V, U> U zip(final Collection<K> kk, final Collection<V> vv, final U identity,
                final BiFunction<U, Tuple2<K, V>, U> accumulator, final BinaryOperator<U> combiner) {
            return zip(kk, vv, true).stream().reduce(identity, accumulator, combiner);
        }

        /**
         * 拼接成一个键值对 recycle 默认循环补位
         * 
         * @param <K>         1号位置元素类型
         * @param <V>         2号位置元素类型
         * @param <U>         返回的结果类型
         * @param kk          1号位置元素集合数组
         * @param vv          2号位置元素结合数组 recycle 是否进行循环补位
         * @param identity    起始点
         * @param accumulator 累加器
         * @param combiner    中间值合并器
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         * @return
         */
        public static <K, V, U> U zip(final K[] kk, final V[] vv, final U identity,
                final BiFunction<U, Tuple2<K, V>, U> accumulator, final BinaryOperator<U> combiner) {
            return zip(Arrays.asList(kk), Arrays.asList(vv), true).stream().reduce(identity, accumulator, combiner);
        }

        /**
         * 拼接成一个键值对 recycle 默认循环补位
         * 
         * @param <K> 1号位置元素类型
         * @param <V> 2号位置元素类型
         * @param kk  1号位置元素集合数组
         * @param vv  2号位置元素结合数组
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> List<Tuple2<K, V>> zip(final K[] kk, final V[] vv) {
            return zip(Arrays.asList(kk), Arrays.asList(vv), true);
        }

        /**
         * 拼接成一个键值对 recycle 默认循环补位
         * 
         * @param <K> 1号位置元素类型
         * @param <V> 2号位置元素类型
         * @param kk  1号位置元素集合数组
         * @param vv  2号位置元素结合数组
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> Stream<Tuple2<K, V>> zip2tups(final K[] kk, final V[] vv) {
            return zip2stream(kk, vv, true);
        }

        /**
         * 拼接成一个键值对 recycle 默认循环补位
         * 
         * @param <K> 1号位置元素类型
         * @param <V> 2号位置元素类型
         * @param kk  1号位置元素集合数组
         * @param vv  2号位置元素结合数组
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> Stream<Tuple2<K, V>> zip2tups(final Stream<K> kk, final Stream<V> vv) {
            return zip2stream(kk, vv, true);
        }

        /**
         * 拼接成一个键值对 recycle 默认循环补位
         * 
         * @param <K> 1号位置元素类型
         * @param <V> 2号位置元素类型
         * @param kk  1号位置元素集合数组
         * @param vv  2号位置元素结合数组
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> Stream<Tuple2<K, V>> zip2tups(final Collection<K> kk, final Collection<V> vv) {
            return zip2stream(kk, vv);
        }

        /**
         * 拼接成一个键值对的流 recycle 默认循环补位
         * 
         * @param <K> 1号位置元素类型
         * @param <V> 2号位置元素类型
         * @param kk  1号位置元素集合数组
         * @param vv  2号位置元素结合数组
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> Stream<Tuple2<K, V>> zip2stream(final Collection<K> kk, final Collection<V> vv) {
            return zip(kk, vv, true).stream();
        }

        /**
         * 拼接成一个键值对
         * 
         * @param <K>     1号位置元素类型
         * @param <V>     2号位置元素类型
         * @param kk      1号位置元素集合数组
         * @param vv      2号位置元素结合数组
         * @param recycle 是否进行循环补位
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> Stream<Tuple2<K, V>> zip2stream(final K[] kk, final V[] vv, final boolean recycle) {
            return zip(Arrays.asList(kk), Arrays.asList(vv), recycle).stream();
        }

        /**
         * 拼接成一个键值对 recycle 默认循环补位
         * 
         * @param <K> 1号位置元素类型
         * @param <V> 2号位置元素类型
         * @param kk  1号位置元素集合数组
         * @param vv  2号位置元素结合数组
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> Stream<Tuple2<K, V>> zip2stream(final K[] kk, final V[] vv) {
            return zip(Arrays.asList(kk), Arrays.asList(vv), true).stream();
        }

        /**
         * 拼接成一个键值对 recycle 默认循环补位
         * 
         * @param <K>     1号位置元素类型
         * @param <V>     2号位置元素类型
         * @param kk      1号位置元素集合数组
         * @param vv      2号位置元素结合数组
         * @param recycle 是否进行循环补位
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> Stream<Tuple2<K, V>> zip2stream(final Stream<K> kk, final Stream<V> vv,
                final boolean recycle) {
            return zip(kk.collect(Collectors.toList()), vv.collect(Collectors.toList()), true).stream();
        }

        /**
         * 拼接成一个键值对的流 recycle 默认循环补位
         * 
         * @param <K>     1号位置元素类型
         * @param <V>     2号位置元素类型
         * @param kk      1号位置元素集合数组
         * @param vv      2号位置元素结合数组
         * @param recycle 是否进行循环补位
         * @return [[k1,v1],[k2,v2],...] 的二元组集合。
         */
        public static <K, V> Stream<Tuple2<K, V>> zip2stream(final Collection<K> kk, final Collection<V> vv,
                final boolean recycle) {
            return zip(kk, vv, true).stream();
        }

        /**
         * tup collector, mapper 的数据类型为 List
         *
         * @param <P>    Tuple2类型的数据类型
         * @param <K>    键名
         * @param <V>    值
         * @param <U>    结果类型
         * @param mapper 映射对象
         * @return U类型的结果
         */
        public static <P extends Tuple2<K, V>, K, V, U> Collector<P, ?, U> tupclc(final Function<List<Tuple2<K, V>>, U> mapper) {
            return Collector.of(LinkedList::new, List::add, (aa, bb) -> {
                aa.addAll(bb);
                return aa;
            }, mapper);
        }

        /**
         * tup collector , mapper 的数据类型为 Stream
         *
         * @param <P>    Tuple2类型的数据类型
         * @param <K>    键名
         * @param <V>    值
         * @param <U>    结果类型
         * @param mapper 映射对象
         * @return U类型的结果
         */
        public static <P extends Tuple2<K, V>, K, V, U> Collector<P, ?, U> tupSclc(final Function<Stream<Tuple2<K, V>>, U> mapper){
            return tupclc(ll->mapper.apply(ll.stream()));
        }

        /**
         * 把一个列表拆分成 (head,tail) 结构.
         * 只有一个元素的列表 [a] 返回 (a,[]) <br>
         *
         * @param <V>  元素类型
         * @param list 列表元素
         * @return (v, [v])
         */
        public static <V> Tuple2<V, List<V>> head2tail(final List<V> list) {
            if (list == null) return null;
            if (list.size() < 2) return TUP2(list.size() < 1 ? null : list.get(0), Collections.emptyList());

            final var x = split(list, 0);
            return TUP2(x._1.get(0), x._2());
        }

        /**
         * 把一个列表拆分成 (initial,last) 结构 <br>
         * 只有一个元素的列表 [a] 返回 ([a],null) <br>
         *
         * @param <V>  元素类型
         * @param list 列表元素
         * @return ([v], v)
         */
        public static <V> Tuple2<List<V>, V> initial2last(final List<V> list) {
            if (list == null) return null;
            if (list.size() < 2) return TUP2(list, null);
            final var x = split(list, list.size() - 2);
            return TUP2(x._1(), x._2().get(0));
        }

        /**
         * 把一个列表拆分成 一个kvpair
         *
         * @param <V>  元素类型
         * @param list 列表元素
         * @param n    把 索引(从0开始)大于等于n 的元素放置到 list2
         * @return (list1, list2)
         */
        public static <V> Tuple2<List<V>, List<V>> split(final List<V> list, int n) {
            return split(list, (idx, v) -> idx <= n);
        }

        /**
         * 把一个列表拆分成 一个kvpair
         *
         * @param <V>       元素类型
         * @param list      列表元素
         * @param predicate (index,v)->boolean, true 表示 list1,false 表示 list2 ,索引从0开始
         * @return (list1, list2)
         */
        public static <V> Tuple2<List<V>, List<V>> split(final List<V> list, final BiPredicate<Integer, V> predicate) {
            final var itr = list.iterator();
            final var list1 = new LinkedList<V>();
            final var list2 = new LinkedList<V>();
            var i = 0;
            while (itr.hasNext()) {
                final var elem = itr.next();
                (predicate.test(i++, elem) ? list1 : list2).add(elem);
            }
            return TUP2(list1, list2);
        }

        /**
         * make list <br>
         * 使用pattern 把一个字符串分解成 列表
         *
         * @param pattern 分解模式,默认的 分隔标识为 "[\\s,/\\.\\\\]+"
         * @return 使用pattern分解list
         */
        public static Function<String, List<String>> mkll(final String pattern) {
            final var defaultPattern = "[\\s,/\\.\\\\]+";
            return line -> Arrays.asList(line.split(pattern == null ? defaultPattern : pattern));
        }
        
        private static final long serialVersionUID = -9103479443503056191L;
        private T _1; // 1号位置元素
        private U _2; // 2号位置元素
    }

    /**
     * 三元组
     *
     * @param <T> 第一元素类型
     * @param <U> 第二元素类型
     * @param <U> 第三元素类型
     * @author gbench
     */
    public static class Tuple3<T, U, V> {

        public Tuple3() {
        }

        public Tuple3(T t, U u, V v) {
            this._1 = t;
            this._2 = u;
            this._3 = v;
        }

        public T _1() {
            return _1;
        }

        public T _1(T t) {
            return _1 = t;
        }

        public U _2() {
            return _2;
        }

        public U _2(U u) {
            return _2 = u;
        }

        public V _3() {
            return _3;
        }

        public V _3(V v) {
            return _3 = v;
        }

        public Optional<V> __3() {
            return Optional.ofNullable(_3);
        }

        public int hashCode() {
            return _1 == null ? Integer.valueOf(0).hashCode() : this._1().hashCode();
        }

        public boolean equals(Object obj) {
            return _1 != null && _1().equals(obj);
        }

        public String toString() {
            return _1() + " --> " + _2() + " --> " + _3();
        }

        public static <T1, T2, T3> Tuple3<T1, T2, T3> TUP3(T1 _1, T2 _2, T3 _3) {
            return new Tuple3<>(_1, _2, _3);
        }

        /**
         * tup collector
         *
         * @param <K>    键名
         * @param <V>    值
         * @param <U>    结果类型
         * @param mapper 映射对象
         * @return U类型的结果
         */
        public static <K, V, U, O> Collector<Tuple3<K, V, U>, List<Tuple3<K, V, U>>, O> tupclc(
                Function<List<Tuple3<K, V, U>>, O> mapper) {
            return Collector.of(LinkedList::new, List::add, (aa, bb) -> {
                aa.addAll(bb);
                return aa;
            }, mapper);
        }

        private T _1;
        private U _2;
        private V _3;
    }

    /**
     * 二元元素的端点元素,这是一个类似于Lisp CONS 的结构
     *
     * @param <T> 元素的值的类型
     * @author gbench
     */
    public static class Elem<T> extends Tuple2<T,Elem<T>>{

        /**
         * 构造函数
         *
         * @param _1 元素数据
         * @param _2 元素指针（父节点或者next节点【如何理解取决于理解视角】的元素指针）
         */
        public Elem(T _1, Elem<T> _2) {
            super(_1, _2);
        }

        /**
         * 元素数据
         */
        public Elem(T _1) {
            super(_1, null);
        }

        /**
         * 获取属性值
         *
         * @param key
         * @param value
         * @return
         */
        public Elem<T> setAttribute(final Object key, Object value) {
            attributes.put(key, value);
            return this;
        }

        /**
         * 获取属性值
         *
         * @param key 键名
         * @return key对应的属性值
         */
        public Object getAttribute(final Object key) {
            return attributes.get(key);
        }

        /**
         * 获取属性集合
         */
        public Map<Object, Object> getAttributes() {
            return attributes;
        }

        /**
         * 是指属性集合
         */
        public void setAttributes(final Map<Object, Object> attributes) {
            this.attributes = attributes;
        }

        /**
         * 提取元素张成的路径数据
         *
         * @param <T>  数据元素类型
         * @param elem 元素对象
         * @return 元素的路径流
         */
        public static <T> Stream<T> data(final Elem<T> elem) {
            return elem._2() == null
                ? Stream.of(elem._1())
                : Stream.concat(data(elem._2()), Stream.of(elem._1()));
        }

        /**
         * 提取元素张成的路径数据
         *
         * @return 元素的路径流
         */
        public Stream<T> data() {
            return data(this);
        }

        /**
         * 提取元素张成的路径数据
         * 
         * @param <T>  数据元素类型
         * @param elem 元素对象
         * @return 元素elem的路径流
         */
        public static <T> Stream<Elem<T>> data2(final Elem<T> elem){
            return elem._2() == null
                ? Stream.of(elem)
                : Stream.concat(data2(elem._2()),Stream.of(elem));
        }

        /**
         * 提取元素张成的路径数据
         * 
         * @return 元素elem的路径流
         */
        public Stream<Elem<T>> data2() {
            return data2(this);
        }

        /**
         * construct 函数,拼接成 一般链表结构<br>
         * 把t设置为新的路径的 端点元素，尾（叶子节点）节点或首节点，取决于理解实施奥
         * 
         * @param <T>  数据元素类型
         * @param t    端点元素的数据
         * @param elem t 关联的端点元素
         * @return 数据为t的端点元素
         */
        public static <T> Elem<T> cons2(final T t, final Elem<T> elem) {
            return new Elem<>(t, elem);
        }

        /**
         * construct 函数，拼接成 一般链表结构<br>
         * 把t设置为新的路径的 端点元素，尾（叶子节点）节点或首节点，取决于理解实施奥
         * @param t 端点元素的数据
         * @return 数据为t的端点元素
         */
        public Elem<T> cons2(final T t){
            return cons2(t,this);
        }
        
        /**
         * 数据全排列组合<br>
         * final var digits = "0123456789".split(""); <br>
         * cph(Elem::new,Arrays.asList(digits,digits,digits))<br>
         * .map(e->e.data().collect(Collectors.toList()))<br>
         * .forEach(System.out::println);<br>
         * 
         * @param <T>          元素类型
         * @param sss          基础元素数组(SourceS arrayS), 例如
         *                     Arrays.asList(digits,digits,digits)
         * @param elem_creator Elem 的 创建函数,类型为： (t,parent)->Elem&lt;T&gt;
         * @return 新的排列组合列表流
         */
        public static <T> Stream<Elem<T>> cph(final BiFunction<T,Elem<T>,Elem<T>> elem_creator,final List<T[]> sss){
            if(sss.size()<1){
                System.err.println("基础元素数组列表长度为0,至少需要包含有一个基础元素数组才能够做cph展开！");
                return Stream.of();
            }

            return sss.size()<2
            ? Stream.of(sss.get(sss.size()-1)).map(e->elem_creator.apply(e, null))
            : cph(elem_creator,sss.subList(0,sss.size()-1))
                .flatMap(p->Stream.of(sss.get(sss.size()-1)).map(e->elem_creator.apply(e, p)));// p:parent,e:elem
        }

        /**
         * 数据全排列组合<br>
         * final var digits = "0123456789".split(""); <br>
         * cph(Elem::new,digits,digits,digits)<br>
         * .map(e->e.data().collect(Collectors.toList()))<br>
         * .forEach(System.out::println);<br>
         * 
         * @param <T>          元素类型
         * @param sss          基础元素数组(SourceS arrayS), 例如
         *                     Arrays.asList(digits,digits,digits)
         * @param elem_creator Elem 的创建函数 类型为： (t,parent)->Elem&lt;T&gt;
         * @return 新的排列组合列表流
         */
        @SafeVarargs
        public static <T> Stream<Elem<T>> cph(final BiFunction<T,Elem<T>,Elem<T>> elem_creator,final T[]... sss){
            final BiFunction<T,Elem<T>,Elem<T>>  default_elem_creator = Elem::new;
            return cph(elem_creator == null ? default_elem_creator : elem_creator, Arrays.asList(sss));
        }

        /**
         * 数据全排列组合<br>
         * final var digits = "0123456789".split(""); <br>
         * cph(digits,digits,digits)<br>
         * .map(e->e.data().collect(Collectors.toList()))<br>
         * .forEach(System.out::println);<br>
         * 
         * @param <T> 元素类型
         * @param sss 基础元素数组(SourceS arrayS), 例如 Arrays.asList(digits,digits,digits)
         * @return 新的排列组合列表流
         */
        @SafeVarargs
        public static <T> Stream<Elem<T>> cph(final T[] ...sss){
            return cph(Elem::new,Arrays.asList(sss));
        }
        
        /**
         * 数据全排列组合<br>
         * final var digits = "0123456789".split(""); <br>
         * cph(Arrays.asList(digits,digits,digits))<br>
         * .map(e->e.data().collect(Collectors.toList()))<br>
         * .forEach(System.out::println);<br>
         * 
         * @param <T> 元素类型
         * @param sss 基础元素数组(SourceS arrayS), 例如 Arrays.asList(digits,digits,digits)
         * @return 新的排列组合列表流
         */
        public static <T> Stream<Elem<T>> cph(final List<T[]> sss) {
            return cph(Elem::new, sss);
        }
        
        /**
         * 数据全排列组合：<br>
         * final var digits = "0123456789".split(""); <br>
         * cph2(Arrays.asList(digits,digits,digits)).forEach(System.out::println);<br>
         * 
         * @param <T> 元素类型
         * @param sss 基础元素数组(SourceS arrayS), 例如 Arrays.asList(digits,digits,digits)
         * @return 新的排列组合列表流
         */
        public static <T> Stream<List<T>> cph2(final List<T[]> sss) {
            return cph(Elem::new, sss).map(e -> e.data().collect(Collectors.toList()));
        }
        
        /**
         * 数据全排列组合：<br>
         * final var digits = "0123456789".split(""); <br>
         * cph2(digits,digits,digits).forEach(System.out::println);<br>
         * 
         * @param <T> 元素类型
         * @param sss 基础元素数组(SourceS arrayS), 例如 :digits,digits,digits
         * @return 新的排列组合列表流
         */
        @SafeVarargs
        public static <T> Stream<List<T>> cph2(final T[]... sss) {
            return cph(Elem::new, Arrays.stream(sss).collect(Collectors.toList()))
                    .map(e -> e.data().collect(Collectors.toList()));
        }
        
        /**
         * 数据全排列组合：<br>
         * final var digits = "0123456789".split(""); <br>
         * cph2(REC("a",digits,"b",digits) <br>
         * .filter(p->p.value().getClass().isArray()) <br>
         * .reduce(p->(Stream&lt;String[]&gt;)Stream.of(p._2()),Stream.of(),Stream::concat))
         * .forEach(System.out::println);<br>
         * 
         * @param <T>    元素类型
         * @param stream 基础元素数组(SourceS arrayS), 例如 :digits,digits,digits
         * @return 新的排列组合列表流
         */
        public static <T> Stream<List<T>> cph2(final Stream<T[]> stream) {
            return cph(Elem::new, stream.collect(Collectors.toList())).map(e -> e.data().collect(Collectors.toList()));
        }
        
        /**
         * 数据全排列组合：<br>
         * final var digits = Arrays.asList("0123456789".split("")); <br>
         * cph2(digits,digits).forEach(System.out::println);<br>
         * 
         * @param <T> 元素类型
         * @param ll  基础元素数组(SourceS List),每个元素都是一个列表, 例如 :digits,digits,digits
         * @return 新的排列组合列表流
         */
        @SuppressWarnings("unchecked")
        @SafeVarargs
        public static <T> Stream<List<T>> cph2(final List<T>... ll) {

            return cph2(Arrays.stream(ll).map(e -> e.toArray(n -> (T[]) Array.newInstance(componentType(e), n))));
        }
        
        /**
         * 获取列表的元素类型类
         * 
         * @param <T> 元素类型
         * @param ll  元素列表,当ll为空或是长度小于1的时候,返回 null
         * @return 元素的类型类
         */
        @SuppressWarnings("unchecked")
        public static <T> Class<T> componentType(final List<T> ll) {
            if (ll == null || ll.size() < 1)
                return null;
            final var componentType = ll.stream().filter(Objects::nonNull).findFirst().map(e -> (Class<T>) e.getClass())
                    .orElse((Class<T>) Object.class);
            return componentType;
        }

        /**
         * 序列号
         */
        private static final long serialVersionUID = -4970370960765747394L;

        private Map<Object, Object> attributes = new HashMap<>();// 属性存储
    }

    /**
     * 理论上 KVPair对应了与 Tuple2是一一对应的，那为何 还要单独设计 一个 KVPair结构呢。<br>
     * KVPair 的特点 就是 为Tuple2 制定了 一种 默认的 操作位置即2号位置，我们把这个位置 value 位置<br>
     * 一些函数 比如 val2rec,corece,map等都是默认对value进行操作的。 <br>
     * 所以KVPair 是一种带有默认 位置的 Tuple2 <br>
     * 
     * 键值对儿：可以把Key-Value 视为一个值的包装器，或者是一个 单值的容器。为一个值贴上了衣蛾key的标签。 <br>
     * Key-Value 是最简单的一个 值Value容器:单值容器。二IRecord是一个多值多键容器。 <br>
     * 需要好注意 当 key为一条代表层级的路径 path 的时候, KVPair就可以用来表达 一条具有层级性质的信息 Path2Value<br>
     * 一组Path2Value的 就可以表达一个属性结构比如:<br>
     * L( KVP("/国务院/卫生部",REC("部长","张三")), KVP("/国务院/工业部",REC("部长","李四") ) 就表示了 <br>
     * 国务院 <br>
     * &nbsp; &nbsp; 卫生部 --- 部长:张三 <br>
     * &nbsp; &nbsp; 工业部 --- 部长:李四 <br>
     * 特别是当 <br>
     * 
     * @author gbench
     *
     * @param <K> 键名类型
     * @param <V> 值类型
     */
    public static class KVPair<K,V> extends Tuple2<K,V>{
        
        /**
         * 键值对儿
         * 
         * @param tup 二元组对象
         */
        public KVPair(Tuple2<K, V> tup) {
            super(tup._1, tup._2);
        }

        /**
         * 键值对儿
         * 
         * @param key   键名
         * @param value 键值
         */
        public KVPair(K key, V value) {
            super(key, value);
        }

        /**
         * 获取键名
         * 
         * @return 键名
         */
        public K key() {
            return this._1();
        }

        /**
         * 设置键名
         * 
         * @param k 键名的值
         * @return 设置后的键名的值
         */
        public K key(K k) {
            return this._1(k);
        }

        /**
         * 获取当前的值
         * 
         * @return
         */
        public V value() {
            return this._2();
        }

        /**
         * 交换1号与2号位置 (k,v)->(v,k) <br>
         * 
         * @return (v,k)
         */
        public KVPair<V, K> swap() {
            return KVP(this._2(), this._1());
        };

        /**
         * 设置当前的值为v
         * 
         * @param v 值
         * @return 设置后的值
         */
        public V value(final V v) {
            return this._2(v);
        }

        /**
         * 设置当前的值为v
         * 
         * @param <U>    结果类型
         * @param mapper 映射函数
         * @return 设置后的值
         */
        public <U> U key(final Function<K, U> mapper) {
            return this._1(mapper);
        }

        /**
         * 把 key 强制类型转换成U类型对象:这当key是Object对象的时候有用
         * 
         * @param <U>    uclass
         * @param uclass 结果类型
         * @return U 类型的对象
         */
        public <U> U key(Class<U> uclass) {
            return this._1(uclass);
        }

        /**
         * 
         * 把 key 视为X类型 给予 应用mapper 函数进行变换，当 vlalue 为 Object的时候很有用
         * 
         * @param <X>    mapper的参数类型
         * @param <U>    mapper的结果
         * @param mapper 变换函数
         * @return U 类型的对象
         */
        @SuppressWarnings("unchecked")
        public <X, U> U key2(final Function<X, U> mapper) {
            return mapper.apply((X) this._1());
        }

        /**
         * 把value值根据指定方法 mapper 进行变换
         * 
         * @param <U>    mapper的结果
         * @param mapper 变换函数
         * @return U 类型的对象
         */
        public <U> U map(final Function<V, U> mapper) {
            return this._2(mapper);
        }

        /**
         * 把 value 视为X类型 给予 应用mapper 函数进行变换，当 vlalue 为 Object的时候 很有用.这是 value2的别名
         * 
         * @param <U>    mapper的结果
         * @param mapper 变换函数
         * @return U 类型的对象
         */
        public <X, U> U map2(final Function<X, U> mapper) {
            return this.value2(mapper);
        }

        /**
         * map的别名 把value值根据指定方法 mapper 进行变换
         * 
         * @param <U>    mapper的结果
         * @param mapper 变换函数
         * @return U 类型的对象
         */
        public <U> U value(final Function<V, U> mapper) {
            return map(mapper);
        }

        /**
         * 
         * 把 value 视为X类型 给予 应用mapper 函数进行变换，当 vlalue 为 Object的时候很有用
         * 
         * @param <X>    mapper的参数类型
         * @param <U>    mapper的结果
         * @param mapper 变换函数
         * @return U 类型的对象
         */
        @SuppressWarnings("unchecked")
        public <X, U> U value2(final Function<X, U> mapper) {
            return mapper.apply((X) this._2());
        }

        /**
         * 把值转换成IRecord：当值是IRecord类型直接返回,是Map类型是采用REC包装返回，其他类型 返回 null.<br>
         * 
         * @return IReord类型的值对象。
         */
        public IRecord val2rec() {
            if (this.value() instanceof IRecord) return (IRecord) this.value();
            else if (this.value() instanceof Map) return REC((Map<?, ?>) this.value());
            else return null;
        }

        /**
         * 把value 强制类型转换成U类型对象:这当value 是 Object对象的时候有用
         * 
         * @param <U>    结果类型类型
         * @param uclass 结果类型类型类
         * @return U 类型的对象
         */
        public <U> U value(final Class<U> uclass) {
            return this._2(uclass);
        }
        
        /**
         * 把value 强制类型转换成U类型对象:这当value 是 Object对象的时候有用
         * @param <U> 结果类型
         * @param uclass 结果类型
         * @return U 类型的对象
         */
        public <U> U corece(Class<U> uclass){
            return value(uclass);
        }
        
        /**
         * 实现 mutator.apply(this)
         * 
         * @param mutator 映射函数
         */
        public <U> U mutate(final Function<KVPair<K, V>, U> mutator) {
            return mutator.apply(this);
        }

        /**
         * 把 key 视为 一个 Function<V,U> 函数，调用 用 value 来调用 key行数 获取执行结果。<br>
         * 即 实现 一个 key(value) 形式的 数据调用 <br>
         * U类型 需要在 语句外部指定例如 final var Integer = kvp.evaluate(); <br>
         * 
         * @param <T> key 的函数类型是一个 K->U 类型函数，这是 一个辅助类型，不需要传递的。
         * @param <U> 返回的结果类型
         * @return U 类型的数据对象
         */
        @SuppressWarnings("unchecked")
        public <T extends Function<V, U>, U> U evaluate() {
            return ((T) this.key()).apply(this.value());
        }

        /**
         * 把 key 视为 一个 Function<V,U> 函数，调用 用 value 来调用 key行数 获取执行结果。<br>
         * 
         * @param <T>    key 的函数类型
         * @param <U>    结果类型
         * @param uclazz 结果类的类型 class
         * @return U 类型的数据对象
         */
        public <T extends Function<V, U>, U> U evaluate(final Class<U> uclazz) {
            return this.evaluate();
        }

        /**
         * Functor 函数
         * 
         * @param <X>    目标结果第一位置 类型
         * @param <Y>    目标结果第二位置 类型
         * @param mapper 变换函数 (t,u)->(x,y)
         * @return (x,y)二元组
         */
        public <X, Y> KVPair<X, Y> fmapK(final Function<KVPair<K, V>, KVPair<X, Y>> mapper) {
            return mapper.apply(this);
        }

        /**
         * 使用指定变换函数 去 变换各个位置上的 元素内容，并生成一个新的 对象
         * 
         * @param <X> 结果的1号 位置类型
         * @param <Y> 结果的2号位置类型
         * @param k2x 1号位置的变换函数
         * @param v2y 2号位置的变换函数
         * @return KVP(X,Y) 类型的对象。
         */
        public <X, Y> KVPair<X, Y> fmap(final Function<K, X> k2x, final Function<V, Y> v2y) {
            return KVP(super.fmap(k2x, v2y));
        }

        /**
         * 使用指定变换函数 去 变换各个位置上的 元素内容，并生成一个新的 对象
         * 
         * @param <X> 结果的1号 位置类型
         * @param k2x 1号位置的变换函数
         * @return KVP(X,U) 类型的对象。
         */
        public <X> KVPair<X, V> fmap1(final Function<K, X> k2x) {
            return KVP(super.fmap1(k2x));
        }

        /**
         * 使用指定变换函数 去 变换各个位置上的 元素内容，并生成一个新的 对象：对于 Object类型的数据很有用。比如 IRecord的kvps
         * 
         * @param <X>   结果的1号 位置类型
         * @param clazz X 的数据类型
         * @return KVP(X,U) 类型的对象。
         */
        public <X> KVPair<X, V> fmap1(Class<X> clazz) {
            return this.fmap1(FC(clazz));
        }

        /**
         * 使用指定变换函数 去 变换各个位置上的 元素内容，并生成一个新的 对象
         * 
         * @param <Y> 结果的2号位置类型
         * @param v2y 2号位置的变换函数
         * @return KVP(T,Y) 类型的对象。
         */
        public <Y> KVPair<K, Y> fmap2(final Function<V, Y> v2y) {
            return KVP(super.fmap2(v2y));
        }

        /**
         * 使用指定变换函数 去 变换各个位置上的 元素内容，并生成一个新的 对象:对于 Object类型的数据很有用。比如 IRecord的kvps
         * 
         * @param <Y>   结果的2号位置类型
         * @param clazz 目标类型的结果
         * @return KVP(T,Y) 类型的对象。
         */
        public <Y> KVPair<K, Y> fmap2(final Class<Y> clazz) {
            return this.fmap2(FC(clazz));
        }

        /**
         * 格式化输出
         */
        public String toString() {
            return MFT("({0}:{1})", _1(), _2());
        }

        /**
         * 把一个列表拆分成 (head,tail) 结构. 只有一个元素的列表 [a] 返回 (a,[]) <br>
         * 
         * @param <V>  元素类型
         * @param list 列表元素
         * @return (v,[v])
         */
        public static <V> KVPair<V, List<V>> head2tail(final List<V> list) {
            return new KVPair<>(Tuple2.head2tail(list));
        }

        /**
         * 把一个列表拆分成 (initial,last) 结构 <br>
         * 只有一个元素的列表 [a] 返回 ([a],null) <br>
         * 
         * @param <V>  元素类型
         * @param list 列表元素
         * @return ([v],v)
         */
        public static <V> KVPair<List<V>, V> initial2last(final List<V> list) {
            return new KVPair<>(Tuple2.initial2last(list));
        }

        /**
         * 把一个列表拆分成 一个tuple
         * 
         * @param <V>  元素类型
         * @param list 列表元素
         * @param n    把 索引(从0开始)大于等于n 的元素放置到 list2
         * @return (list1,list2)
         */
        public static <V> Tuple2<List<V>, List<V>> split(final List<V> list, int n) {
            return new KVPair<>(Tuple2.split(list, n));
        }

        /**
         * 把一个列表拆分成 一个tuple
         * 
         * @param <V>       元素类型
         * @param list      列表元素
         * @param predicate (index,v)->boolean, true 表示 list1,false 表示 list2 ,索引从0开始
         * @return (list1,list2)
         */
        public static <V> KVPair<List<V>, List<V>> split(final List<V> list, final BiPredicate<Integer, V> predicate) {
            return new KVPair<>(Tuple2.split(list, predicate));
        }

        /**
         * 创建一个键值对儿
         * 
         * @param <K1> 键类型
         * @param <V1> 值类型
         * @param k1   键名
         * @param v1   键值
         * @return 键值对儿(k1,v1)
         */
        public static <K1, V1> KVPair<K1, V1> KVP(final K1 k1, final V1 v1) {
            return new KVPair<>(k1, v1);
        }

        /**
         * 创建一个键值对儿
         * 
         * @param <K1>   键类型
         * @param <V1>   值类型
         * @param tuple2 2元组类型
         * @return 键值对儿(k1,v1)
         */
        public static <K1, V1> KVPair<K1, V1> KVP(final Tuple2<K1, V1> tuple2) {
            return new KVPair<>(tuple2);
        }

        /**
         * 创建一个键值对儿
         *
         * @param <T> 元素类型
         * @param tt  键值序列
         * @return 键值对儿(tt[0], tt[1])
         */
        public static <T> KVPair<T, T> KVP(final T[] tt) {
            if (tt == null || tt.length < 1) return null;
            final var n = tt.length;
            return new KVPair<>(tt[0 % n], tt[1 % n]);
        }

        /**
         * kvp collector , List 类型的 mapper
         *
         * @param <P>    KVPair 类型的数据类型
         * @param <K>    键名
         * @param <V>    值
         * @param <U>    结果类型
         * @param mapper 映射对象
         * @return U类型的结果
         */
        public static <P extends KVPair<K, V>, K, V, U> Collector<P, ?, U> kvpclc(final Function<List<KVPair<K, V>>, U> mapper) {
            
            return Collector.of(LinkedList::new, List::add, (aa, bb) -> {
                aa.addAll(bb);
                return aa;
            }, mapper);
        }

        /**
         * kvp collector , Stream 类型的 mapper
         *
         * @param <P>    KVPair 类型的数据类型
         * @param <K>    键名
         * @param <V>    值
         * @param <U>    结果类型
         * @param mapper 映射对象
         * @return U类型的结果
         */
        public static <P extends KVPair<K, V>, K, V, U> Collector<KVPair<K, V>, ?, U> kvpSclc(final Function<Stream<KVPair<K, V>>, U> mapper) {
            
            return kvpclc(ll -> mapper.apply(ll.stream()));
        }

        private static final long serialVersionUID = 1110300882502209203L;
    }

    /**
     *
     * @author gbench
     *
     * @param <V> 元素类型
     */
    public interface IColumn<V> {
        /**
         * 獲得第個元素
         * 
         * @param i 元素編號，從0開始
         * @return 元素内容
         */
        V get(final int i);

        /**
         * 添加一個元素
         * 
         * @param v
         */
        void add(final V v);

        /**
         * 添加一個元素
         * 
         * @param v 元素对象
         */
        void addObject(final Object v);

        /**
         * 獲得初始類型
         * 
         * @return 类元素类型
         */
        Class<V> getType();
    }
    
    /**
     * 表达式计算器
     * 
     * @author gbench
     *
     */
    public static class ExpressionEvaluator {

        /**
         * 表达式计算
         * 
         * @param line 表达式的行
         * @return 表达式计算的结果
         */
        public Object eval(String line) {
            try {
                return engine.eval(line);
            } catch (ScriptException e) {
                e.printStackTrace();
            }
            return null;
        }

        /**
         * 计算表达式的数值
         * 
         * @param expression 机械
         * @return 双精度
         */
        public Double eval2dbl(String expression) {
            if (expression == null) return null;
            final var result = eval(expression);

            return result == null ? null : Double.valueOf(result.toString());
        }

        private final ScriptEngineManager manager = new ScriptEngineManager();
        private final ScriptEngine engine = manager.getEngineByName("javascript");
    }

    /**
     * 代表一个列数据 其实就是 键值对儿,差别就是这个键值是一个列表数据。
     * @author gbench
     *
     * @param <V> 列中值的类型
     */
    public static class Column<V> extends KVPair<String,List<V>>
            implements IColumn<V>{
        private static final long serialVersionUID = 5783906325810918364L;
        final static int INIT_LIST_SIZE = 100;

        public Column(String name) {
            super(name, new ArrayList<>(INIT_LIST_SIZE));
            this.clazz = null;
        }

        public Column(String name, Class<V> clazz) {
            super(name, new ArrayList<>(INIT_LIST_SIZE));
            this.clazz = clazz;
        }

        public V get( int i) {
            return this.value().get(i);
        }

        public void add(V v) {
            this.value().add(v);
        }

        public Class<V> getType(){
            return this.clazz;
        }

        @SuppressWarnings("unchecked")
        public void setType(Class<?> cls) {
            clazz = (Class<V>) cls;
        }

        /**
         * 添加一個元素
         * @param v
         */
        @SuppressWarnings("unchecked")
        public void addObject(Object v) {
            this.add((V)v);
        }

        /**
         * 格式化數據
         */
        public String toString() {
            String type = this.getType()==null?"unknown":this.getType()
                    .getSimpleName();// 類型名
            return this.key()+"("+type+")"+" -> "+
                    this.value();
        }

        @SuppressWarnings("unchecked")
        public V[] toArray() {
            List<V> vv = this.value();
            if(vv==null)return  null;
            return (V[])vv.toArray();
        }

        private Class<V> clazz = null; // 初始類型
    }

    /**
     * IRecord的序列化方法
     * @author gbench
     *
     */
    public static class IRecordSerializer extends StdSerializer<IRecord>{

        private static final long serialVersionUID = -6713069486531158400L;

        /**
         * 序列化
         */
        protected IRecordSerializer() {
            super(IRecord.class);
        }

        @Override
        public void serializeWithType(IRecord value, JsonGenerator generator ,SerializerProvider provider,
                                      TypeSerializer typeSer) throws IOException {
            this.serialize(value, generator, provider);
        }

        @Override
        public void serialize(IRecord value, JsonGenerator generator, SerializerProvider provider) throws IOException {
            generator.writeStartObject();
            for(KVPair<String,Object> kvp:value.kvs()) generator.writeObjectField(kvp.key(),kvp.value());
            generator.writeEndObject();
        }

    }

    /**
     *
     * @author gbench
     *
     */
    public static class IRecordDeserializer extends StdDeserializer<IRecord>{

        private static final long serialVersionUID = 637227298143614828L;

        /**
         *
         */
        protected IRecordDeserializer() {
            super(IRecord.class);
        }

        /**
         * 单层节点转换的ObjectNode变为IRecord
         * @param node
         * @return
         */
        public static IRecord objnode2rec(ObjectNode node) {
            Map<String,Object> mm = new LinkedHashMap<>();
            node.fieldNames().forEachRemaining(name->mm.put(name, node.get(name)));
            //System.out.println(mm);
            return new LinkedRecord(mm);
        }
        
        /**
         * 单层节点转换的ObjectNode变为IRecord
        * @param node 节点
        * @return
        */
       public static Function<ObjectNode,IRecord> node2rec= IRecordDeserializer::objnode2rec;

        @Override
        public IRecord deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
            
            JsonNode node = jp.getCodec().readTree(jp);
            Map<String,Object> mm = new LinkedHashMap<>();
            node.fieldNames().forEachRemaining(name->{
                JsonNode jsn = node.get(name);
                if(jsn.isObject()) {
                    mm.put(name, objnode2rec((ObjectNode)node.get(name)));
                }else {
                    Object value = jsn;
                    if(jsn.isTextual()) {value = jsn.asText();} else if (jsn.isDouble()){value = jsn.asDouble();}
                    else if (jsn.isInt()){value = jsn.asInt();} else if (jsn.isBoolean()){value = jsn.asBoolean();}
                    else if (jsn.isFloat()){value = jsn.asDouble();} else if (jsn.isLong()){value = jsn.asLong();}//if
                    mm.put(name, value);
                }//if
            });
            return new LinkedRecord(mm);
        }
    }

    /**
     * IRecord 记录结构(键值集合) <br>
     * IRecord 是键值对儿(Key Value Pairs KVPs)的集合 (也可以理解键-值集合 KeyValues kvs)。<br>
     * 其基本单元为一个键值对儿KVP,有时候简写成 pair或p。KVP 是一个(String,Object) <br>
     * 的二元组，需要对于一个kvp的value他是可以为任何类型的。因此也是可以为IRecord的类型， <br>
     * 所以IRecord是一个可以进行递归定义的数据结构。由于IRecord的设计思想来源于LISP的列表。<br>
     * 因此他具有丰富的表达能力。可以表达 列表,树,图 等基础结构。因此可以很容易拼装成其他数据结构。<br>
     * 是一种既具有原子性 又具有集合性的 数据结构。非常适合表达动态定义的概念,同时对静态概念也有很好 <br>
     * 的变换方法 ,比如: mutate,toTarget(有损变换,部分转换),cast(整体转换), <br>
     * OBJINIT,OBJ2REC,OBJ2KVS,P(点数据)等方法，可以很方便的在动态概念与静态概念的之间<br>
     * 的转换。静态概念：结构固定的数据结构，即一旦概念确定，结构的数据成员就拥有了确定类型和数量的概念。<br>
     * 与静态概念相对应 成员的类型与数量不确定的数据的结构就是动态概念。<br>
     * <br>
     * 由于record 就是模仿 LISP语言中的列表（增强了key-value的树形特征）。所以 IRecord <br>
     * 理论上是可以标识任何数据结构的。用一句话来形容 IRecord:IRecord 就是结构化的数据的意思。<br>
     * IRecord 需要具有递归的含义，也就是IRecord的元素也可以是IRecord.
     * <br>
     * IRecord 不仅表现出结构化，还要表现出类似于LISP 列表计算。也就是可以依附于符号(key)<br>
     * 的绑定类型,而表现出值的计算的能力。比如:<br>
     * public default <T,U> U get(String key,T t,Function<T,U> t2u)，<br>
     * 就把一个key,绑定到一个Function<T,U> t2u 然后对vlaue 进行计算。<br>
     * 另外key->value 中的value 不仅可以是数值,还可以是函数。<br>
     * 这样key:value 就不是一个静态意义，而是一个动态的概念了。比如：<br>
     * &nbsp;interface FOO{ void foo();};<br>
     * &nbsp;REC("foo",(FOO)()->{});<br>
     * 
     * @author gbench
     *
     */
    @JsonSerialize(using = IRecordSerializer.class)
    @JsonDeserialize(using = IRecordDeserializer.class)
    public interface IRecord extends Serializable,Comparable<IRecord>{
        
        /**
         * 添加一个新的键值对儿(key,value).根据具体的IRecord的不同 对于已经存在的key：若允许同名字段，则添加新的键值对儿，<br>
         * 若不允许同名key 则修改key的值位vlaue
         * 
         * @param key   字段名: key 会调用 toString作为进行键名转换
         * @param value 字段值 任意对象 可以为null
         * @return 当前的IRecord 以保证可以链式编程。
         */
        IRecord add(Object key, Object value);

        /**
         * 设置键名key的值为vlaue,如果key不存在则添加，否则修改键名key的值为value
         * 
         * @param key   键名
         * @param value 键值 可以为null
         * @return 当前的IRecord 以保证可以链式编程。
         */
        IRecord set(String key, Object value);

        /**
         * 提取字段key 所对应的值
         * 
         * @param key 键名
         * @return 键名字段key 所对应的值
         */
        Object get(String key);

        /**
         * 字段key 所对应的值列表，如果存在多个同名的key 则把这些key的值合并成一个列表。
         * 
         * @param key 字段名
         * @return 字段key 所对应的值列表，如果存在多个同名的key 则把这些key的值合并成一个列表。
         */
        List<Object> gets(String key);

        /**
         * 键值序{(k0,v0),(k1,v1),...}
         * 
         * @return 键值序{(k0,v0),(k1,v1),...}
         */
        Stream<KVPair<String, Object>> stream();

        /**
         * 键值序{(k0,v0),(k1,v1),...}
         * 
         * @return 键值序{(k0,v0),(k1,v1),...}
         */
        List<KVPair<String, Object>> kvs();

        /**
         * 键值序{(k0,v0),(k1,v1),...}
         * 
         * @return 键值序{(k0,v0),(k1,v1),...}
         */
        Map<String, Object> toMap();

        /**
         * 复制当前IRecord，即做一个当前实例的拷贝:这是一个浅拷贝。仅当对字段值进行拷贝，不对字段值的属性进行进一步拷贝。
         */
        IRecord duplicate();// 复制克隆
        
        /////////////////////////////////////////////////////////////////////
        // 以下是IRecord 的默认方法区域
        /////////////////////////////////////////////////////////////////////
        
        /**
         * 添加一个新的键值对儿(key,value).根据具体的IRecord的不同 对于已经存在的key：若允许同名字段，<br>
         * 则添加新的键值对儿，若不允许同名key则修改key的值位value <br>
         * 
         * @param kvp 键值对儿对象
         * @return 当前的IRecord 以保证可以链式编程。
         */
        default IRecord add(final KVPair<String, ?> kvp) {
            return this.add(kvp.key(), kvp.value());
        }
        
        /**
         * 把键值序列 变换成一个T类型的数据流。
         * 
         * @param <T> 结果的数据类型
         * @param mapper kvp 的变换函数
         * @return T 类型的数据流
         */
        default <T> Stream<T> stream(final Function<KVPair<String, Object>, T> mapper){
            @SuppressWarnings("unchecked")
            final Function<KVPair<String,Object>,T> fmapper = mapper==null?e->(T)e:mapper;// 变换函数
            return this.stream().map(fmapper);
        }
        
        /**
         * 键值对儿的个数
         * @return 键值对儿的个数
         */
        default int size() {
            return this.keys().size();
        }
        
        /**
         * 是否含有key字段
         * @param key 字段名称
         * @return boolean 包含true:不包含false
         */
        default boolean has(final String key) {
            if(key==null||this.keys().size()<1)return false;
            return this.keys().contains(key);
        }
        
        /**
         * 判断是否为一个空记录：IRecord.如果没有一个key就是一个空对象。
         * @return 空记录标记。
         */
        default boolean isEmpty() {
            return this.keys().size()<=0;
        }
        
        /////////////////////////////////////////////////////////////////////
        // 以下是IRecord 的默认方法区域
        /////////////////////////////////////////////////////////////////////
        
        /**
         * 提取第一个键名元素数据
         * @param <T> 默认值类型
         * @param default_value 默认值
         * @return T类型值
         */
        default <T> T car(T default_value) {
            @SuppressWarnings("unchecked")
            final var obj = (T)this.get(0);
            return obj==null? default_value:obj;
        }
        
        /**
         * 提取第一个键名元素数据
         * @param <T> 默认值类型
         * @return T类型值
         */
        default <T> Object car() {
            return this.car(null);
        }
        
        /**
         * 提取除掉第一元素之后的内容
         * @return IRecord
         */
        default <T> IRecord cdr() {
            return IRecord.KVS2REC(this.stream().skip(1));
        }
        
        /**
         * 提取字段key 所对应的值
         * @param <T> 值类型
         * @param key 键名
         * @param default_value 默认值
         * @return 键名字段key 所对应的值
         */
        @SuppressWarnings("unchecked")
        default <T> T get(String key, T default_value) {
            final var obj = (T)this.get(key);
            return obj==null? default_value:obj;
        }
        
        /**
         * 提取指定類型的字段<br>
         * 提取字段並把字段指定轉換到targetType 
         * @param <T> 目標類型
         * @param key 字段名，鍵名
         * @param targetType 目標類型
         * @return 键名字段key 所对应的值
         */
        default <T> T getT(String key, final Class<T> targetType) {
            final var targetValue = REC(0,this.get(key)).toTarget(targetType);
            return targetValue;
        }
        
        /**
         * 提取指定類型的字段
         * 提取字段並把字段指定轉換到targetType <br>
         * @param <T> 目標類型
         * @param idx 字段名，鍵名 索引 從0開始
         * @param targetType 目標類型
         * @return 键名字段索引 idx 所对应的值
         */
        default <T> T getT(Integer idx, final Class<T> targetType) {
            final var targetValue = REC(0,this.get(idx)).toTarget(targetType);
            return targetValue;
        }
        
        /**
         * 提取字段idx索引 所对应的值
         * @param <T> 
         * @param idx 键名索引从0开始
         * @param default_value 默认值
         * @return 键名字段key 所对应的值
         */
        @SuppressWarnings("unchecked")
        default <T> T get(int idx, T default_value) {
            final var obj = (T)this.get(this.idx2key(idx));
            return obj==null? default_value:obj;
        }
        
        /**
         * 按照 索引进行字段 取值
         * @param idx 从0开始
         * @return idx 所标识的字段的值,非法索引(超出范围) 返回null
         */
        default Object get(final Integer idx) {
            final String key = this.idx2key(idx);
            return key==null?null:get(key);
        }

        /**
         * 使用bb 筛选键值对儿: 比如 提取水果的所有子集 <br>
         * final var rec = STRING2REC("苹果,西瓜,草莓,哈密瓜,鸭梨");// 水果列表 <br>
         * cph2(RPT(rec.size(),L(true,false))).map(e->rec.gets(e.bools())).map(e->MFT("{0}",e.values())) <br>
         * .forEach(System.out::println); <br>
         * 
         * @param bb 下标选择器,当 bb 为 null或 长度小于等于0返回空记录，即 REC()
         * @return bb 所筛选出来的对应字段
         */
        default IRecord gets(final Boolean... bb) {
            final IRecord rec = REC();
            if (bb != null) {
                final var n = bb.length;
                final var ai = new AtomicInteger(0);
                if (n <= 0) {
                    return rec;
                } else {
                    this.kvs().forEach(p -> {
                        final var i = ai.getAndIncrement() % n;
                        if (bb[i]) {
                            rec.add(p._1(), p._2());
                        }
                    });// forEach
                }
            } // if
            return rec;
        }
        
        /**
         * 这是按照indexes 所指定的键值进行数据过滤。默认过滤空值字段（该字段的值value为null,或者非法的索引位置)
         * 
         * @param indexes 提取的字段键名索引序列,非负整数从0开始
         * @return 一个SimpleRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord gets(final Number... indexes) {
            final var kk = Arrays.stream(indexes).map(i -> this.idx2key(i.intValue())).filter(Objects::nonNull).toArray(String[]::new);
            final var rec = new SimpleRecord();
            for (String k : kk) {
                final var v = this.get(k);
                if (v != null) rec.add(k, v);
            }

            return rec;
        }

        /**
         * 把key字段的值强制装换成 T 类型。类型强转失败时返回null
         * @param <T> 参照对象的类的类型
         * @param key 字段名称
         * @param targetClass 参照对象的类
         * @return T 类型数据
         */
        @SuppressWarnings("unchecked")
        default <T> T get(final String key, final Class<T> targetClass) {
            return map(key,e->{
                T t1 = null;
                try {t1 = (T)e;}catch(Exception ignored) {}
                return t1;
            });
        }
        
        /**
         * 把index 字段索引位置的值强制装换成 T 类型。类型强转失败时返回null
         * @param idx 字段索引从0开始 
         * @param targetClass 参照对象
         * @return idx 所对应的值
         */
        @SuppressWarnings("unchecked")
        default <T> T get(final int idx, final Class<T> targetClass) {
            return map(idx,e->{
                T t1 = null;
                try {t1 = (T)e;}catch(Exception ignored) {}
                return t1;
            });
        }
        
        /**
         * 比如 对于 一个 REC("numbers",A(1,2,3)).aa("numbers",Integer.class); 可以获取得到 数组类型。<br>
         * 把key字段值强制装换成 T 类型。类型强转失败时返回null<br>
         * @param <T> 参照类的类型
         * @param key 字段名称
         * @param targetClass 类型参照类
         * @return idx 所对应的值
         */
        @SuppressWarnings("unchecked")
        default <T> T[] aa(final String key, final Class<T> targetClass) {
            return map(key,e->{
                T[] tt = null;
                try {tt = (T[])e;}catch(Exception ignored) {}
                return tt;
            });
        }
        
        
        /**
         * 比如 对于 一个 REC("numbers",A(1,2,3)).aa("numbers",Integer.class); 可以获取得到 数组类型。<br>
         * 把index 字段索引位置的值强制装换成 T 类型。类型强转失败时返回null <br>
         * @param <T> 参照类的类型
         * @param idx 字段索引序号 从0开始
         * @param targetClass 类型参照类
         * @return idx 所对应的值
         */
        default <T> T[] aa(final int idx, final Class<T> targetClass) {
            return this.aa(idx2key(idx), targetClass);
        }
        
        /**
         * 比如 对于 一个 REC("numbers",A(1d,2d,3d)).aa("numbers",Double.class); 可以获取得到 数组类型。<br>
         * 把key字段值强制装换成 T 类型。类型强转失败时返回null<br>
         * @param key 字段名称
         * targetClass 类型参照类 默认为 Double.class
         * @return idx 所对应的值
         */
        default Double[] dbls(final String key) {
            return this.aa(key, Double.class);
        }
        
        /**
         * 比如 对于 一个 REC("numbers",A(1d,2d,3d)).aa("numbers",Double.class); 可以获取得到 数组类型。<br>
         * 把key字段值强制装换成 T 类型。类型强转失败时返回null<br>
         * @param idx 字段索引从0开始
         * targetClass 类型参照类 默认为 Double.class
         * @return idx 所对应的值
         */
        default Double[] dbls(final int idx) {
            return this.aa(idx, Double.class);
        }
        
        /**
         * 比如 对于 一个 REC("numbers",A(1l,2l,3l)).aa("numbers",Long.class); 可以获取得到 数组类型。<br>
         * 把key字段值强制装换成 T 类型。类型强转失败时返回null<br>
         * @param key 字段名称
         * targetClass 类型参照类 默认为 Long.class
         * @return idx 所对应的值
         */
        default Long[] lngs(final String key) {
            return this.aa(key, Long.class);
        }
        
        /**
         * 比如 对于 一个 REC("numbers",A(1l,2l,3l)).aa("numbers",Long.class); 可以获取得到 数组类型。<br>
         * 把key字段值强制装换成 T 类型。类型强转失败时返回null<br>
         * @param idx 字段索引从0开始
         * targetClass 类型参照类 默认为 Long.class
         * @return idx 所对应的值
         */
        default Long[] lngs(final int idx) {
            return this.aa(idx, Long.class);
        }
        
        /**
         * 比如 对于 一个 REC("numbers",A(1,2,3)).aa("numbers",Integer.class); 可以获取得到 数组类型。<br>
         * 把key字段值强制装换成 T 类型。类型强转失败时返回null<br>
         * @param key 字段名称
         * targetClass 类型参照类 默认为 Integer.class
         * @return idx 所对应的值
         */
        default Integer[] ints(final String key) {
            return this.aa(key, Integer.class);
        }
        
        /**
         * 比如 对于 一个 REC("numbers",A(1,2,3)).aa("numbers",Integer.class); 可以获取得到 数组类型。<br>
         * 把key字段值强制装换成 T 类型。类型强转失败时返回null<br>
         * @param idx 字段索引从0开始
         * targetClass 类型参照类 默认为 Integer.class
         * @return idx 所对应的值
         */
        default Integer[] ints(final int idx) {
            return this.aa(idx, Integer.class);
        }
        
        /**
         * 比如 对于 一个 REC("numbers",A("1","2","3")).aa("numbers",String.class); 可以获取得到 数组类型。<br>
         * 把key字段值强制装换成 T 类型。类型强转失败时返回null<br>
         * @param key 字段名称
         * targetClass 类型参照类 默认为 String.class
         * @return idx 所对应的值
         */
        default String[] strs(final String key) {
            return this.aa(key, String.class);
        }
        
        /**
         * 比如 对于 一个 REC("numbers",A("1","2","3")).aa(0,String.class); 可以获取得到 数组类型。<br>
         * 把key字段值强制装换成 T 类型。类型强转失败时返回null<br>
         * @param idx 字段索引从0开始
         * targetClass 类型参照类 默认为 String.class
         * @return idx 所对应的值
         */
        default String[] strs(final int idx) {
            return this.aa(idx, String.class);
        }
        
        /**
         * 所谓叶子节点是值：元素类型不是IRecord 或是Map之类的节点。 注意：contact,address 不是叶子节点
         * 比如；<br>
         *  final var rec = REC( <br> 
         *      "name","zhangsan", <br>
         *      "sex","man", <br>
         *      "contact",REC("mobile","13120751773","phone","0411833802234","email","gbench@sina.com"), <br>
         *      "address",REC("provice","liaoning","city","dalian","district","pulandian"));<br>
         *  System.out.println(rec.leafs());<br>
         * 提取所有叶子节点:注意当叶子节点是多元素类型：如List,Set 之类的Collection的时候，只返回Collection中的第一个元素
         * @return 叶子节点集合：
         */
        default List<IRecord> leafs() {
            // 单节点遍历
            return this.dfs_eval_forone(IRecord::REC);
        }
        
        /**
         * 提取第一个叶子节点 <br>
         * 所谓叶子节点是值：元素类型不是IRecord 或是Map之类的节点。 注意：contact,address 不是叶子节点
         * 比如：<br>
         * final var rec = REC( <br> 
         *      "name","zhangsan", <br>
         *      "sex","man", <br>
         *      "contact",REC("mobile","13120751773","phone","0411833802234","email","gbench@sina.com"), <br>
         *      "address",REC("provice","liaoning","city","dalian","district","pulandian")); <br>
         *  System.out.println(rec.leaf()); // "/name:zhangsan" <br>
         *  System.out.println(rec.leaf(3)); // "/contact/phone:0411833802234" <br>
         *  <br>
         * @param n 叶子节点的序号 从0开始,默认为0，如果不输入的化，只返回一个叶子，节点输入多个序号只提取第一个元素
         * @return 第一个叶子姐弟啊
         */
        default IRecord leaf(final Number... n) {
            
           final var final_n = (n==null||n.length<1)?0:n[0].intValue();
           // 单节点遍历
           return this.dfs_eval_forone(IRecord::REC).get(final_n);
        }
        
        /**
         * 按照索引 idx 设置字段的值
         * @param idx 键值索引序号
         * @param value 字段值
         * @return 当前的IRecord 以保证可以链式编程。
         */
        default IRecord set(int idx, Object value) {
            final var key = this.idx2key(idx);
            return this.set(key, value);
        }
        
        /**
         * 把key 所代表的值(value) 变换成 U类型的数据
         *  
         * @param <T> index 所代表的值的类型
         * @param <U> 返回结果的类型
         * 
         * @param key 字段名
         * @param t2u 字段值的变换函数
         * @return U类型数据
         */
        @SuppressWarnings("unchecked")
        default <T,U> U get(final String key, final Function<T, U> t2u) {
            return map(key,e->{
                T t1 = null;
                try {t1 = (T)e;}catch(Exception ignored) {}
                return t2u.apply(t1);
            });
        }
        
        /**
         * 把index 所代表的值(value) 变换成 U类型的数据
         * 
         * @param <T> index 所代表的值的类型
         * @param <U> 返回结果的类型
         * 
         * @param idx 字段名称
         * @param t2u 字段值的变换函数
         * @return U 类型数据
         */
        @SuppressWarnings("unchecked")
        default <T,U> U get(final int idx, final Function<T, U> t2u) {
            return map(idx,e->{
                T t1 = null;
                try {t1 = (T)e;}catch(Exception ignored) {}
                return t2u.apply(t1);
            });
        }
        
        /**
         * 根据路径获取Record 数据值。<br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param t2u 对 record 结果进行转换的函数
         * @return U类型数据值。
         */
        default <T,U> U getByPath(final String path, final Function<T, U> t2u) {
            return getByPath(Arrays.asList(path.split("[/]+")),t2u);
        }
        
        /**
         * 根据路径获取Record 数据值。<br> <br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param targetClass 类型参照类的对象
         * @return U类型数据值。
         */
        @SuppressWarnings("unchecked")
        default <T,U> U getByPath(final String path, final Class<U> targetClass) {
            return getByPath(path,e->(U)e);
        }
        
        /**
         * 根据路径获取Record 数据值。<br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2","/",identity) 返回 value 数值 <br>
         * 
         * @param path 键名序列
         * @param sep 键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param t2u 对 record 结果进行转换的函数
         * @return U类型数据值。
         */
        default <T,U> U getByPath(final String path, String sep, final Function<T, U> t2u) {
            return getByPath(Arrays.asList(path.split(sep)),t2u);
        }
        
        /**
         * 根据路径获取Record 数据值。<br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式 <br>
         * [k0:[ <br>
         *   k1:[ <br>
         *  k2:value]]] <br>
         * getByPath("k0/k1/k2") 返回 value 数值 <br>
         * 
         * @param path 键名序列, 分隔符：sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return U类型数据值。
         */
        default Object getByPath(final String path) {
            return getByPath(Arrays.asList(path.split("[/]+")),identity);
        }
        
        /**
         * 根据路径获取Record 数据值。<br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法<br>
         * ,即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式 <br>
         * [k0:[ <br>
         *   k1:[ <br>
         *  k2:value]]] <br>
         * getByPath("k0/k1/k2","/") 返回 value 数值 <br>
         * 
         * @param path 键名序列
         * @param sep 键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return U类型数据值。
         */
        default Object getByPath(final String path, String sep) {
            return getByPath(Arrays.asList(path.split(sep)),identity);
        }
        
        /**
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式 <br>
         * [k0:[ <br>
         *   k1:[ <br>
         *  k2:value]]] <br>
         * getByPath([k0,k1,k2]) 返回 value 数值
         * 
         * 根据路径获取Record 数据值。<br>依据keys:k0/k1/k2/... 按层次访问元素数据。<br>
         * 
         * @param keys 键名序列
         */
        default Object getByPath(List<String> keys) {
            return this.getByPath(keys,identity);
        }
        
        /**
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式 <br>
         * [k0:[ <br>
         *   k1:[ <br>
         *  k2:value]]] <br>
         * getByPath([k0,k1,k2],identity) 返回 value 数值 <br>
         * 
         * 根据路径获取Record 数据值。<br>依据keys:k0/k1/k2/... 按层次访问元素数据。<br>
         * 
         * @param <T> 节点的数据类型
         * @param <U> 转换结果的数据类型
         * @param keys 键名序列：键名额层级结构
         * @param t2u 对 record 结果进行转换的函数
         * @return U类型数据值。
         */
        @SuppressWarnings("unchecked")
        default <T,U> U getByPath(final List<String> keys, final Function<T, U> t2u) {
            final var kk = keys.stream().filter(e->!e.matches("[\\s/\\\\]*")).collect(Collectors.toList());//
            final var size = kk.size();
            if(size<1)return t2u.apply((T)this);//
            final var obj = this.get(kk.get(0));
            if(kk.size()==1)return t2u.apply((T)obj);
            
            IRecord node = null;// 中间节点数据
            try {
                if(obj instanceof IRecord) {// IRecord 直接转换
                    node = (IRecord)obj;
                }else if (obj instanceof Map) {// 对Map类型 需要通过IRecord 给予简介转换。
                    final var mm = (Map<String,Object>)obj;
                    node = REC(mm);
                }else {
                    return null;
                }
            }catch(Exception e) {// 类型转换出现了异常
                e.printStackTrace();
                return null;
            }
            
            // 步进一级继续按路径检索数据。
            return node.getByPath(kk.subList(1,size),t2u);
        }
        
        /**
         * 根据路径获取Record 数据值。<br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param t2u 对 record 结果进行转换的函数
         * @return U 类型数据值。
         */
        default <T,U> U path2target(final String path, final Function<T, U> t2u) {
            return this.getByPath(path, t2u);
        }
        
        /**
         * 根据路径获取Record 数据值。<br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         * 
         * @param <U> 类型参照类的类型
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param targetClass 类型参照类
         * @return U 类型的数据对象。
         */
        @SuppressWarnings("unchecked")
        default <U> U path2target(final String path, Class<U> targetClass) {
            return this.getByPath(path, e->((U)e));
        }

        /**
         * 根据路径获取Record 数据值。<br> <br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return 整型数组
         */
        default Integer[] path2ints(final String path) {
            return getByPath(path,Integer[].class);
        }

        /**
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return 长整型数组
         */
        default Long[] path2lngs(final String path) {
            return getByPath(path,Long[].class);
        }

        /**
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return 浮点数类型的数组。
         */
        default Double[] path2dbls(final String path) {
            return getByPath(path,Double[].class);
        }

        /**
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return 字符串类型的数组。
         */
        default String[] path2strs(final String path) {
            return getByPath(path,String[].class);
        }
        
        /**
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return Object 类型的结果
         */
        default Object path2obj(final String path) {
            return getByPath(path,Object.class);
        }
        
        /**
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return Object 类型的流
         */
        default Stream<Object> path2stream(final String path) {
            return Stream.of(getByPath(path,Object[].class));
        }
        
        /**
         * 根据路径获取Record 数据值。<br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式 <br>
         * 类似于如下的形式 [k0:[ <br>
         * k1:[ <br>
         * k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <T>    源数据元素类型
         * @param <U>    目标数据元素类型
         * @param path   键名序列,分隔符sep 默认为："[/]+" 键名序列 的分割符号，这样就可以从path中构造出层级关系。<br>
         *               当path不存在的时候,返回一个 长度为0的流。
         * @param mapper 元素变换函数 t->u
         * @return U类型 的流
         */
        default <T,U> Stream<U> path2stream(final String path, final Function<T,U> mapper) {
            @SuppressWarnings("unchecked")
            final Function<Object, U> final_mapper = mapper == null ? e -> (U) e : (Function<Object, U>) mapper;
            final var vv = getByPath(path);// 提取路径值
            return REC("0", vv == null ? new ArrayList<>() : vv)
                .lla("0", Object.class).stream().map(final_mapper); // 构造一个IRecord然后用IRecord的lla计算流
        }
        
        /**
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <U> 目标数据元素类型
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param defaultValue 元素的默认值
         * @return U 类型 的流
         */
        @SuppressWarnings("unchecked")
        default <U> Stream<U> path2stream(final String path, final U defaultValue) {
            final var uclass = defaultValue == null ? Object.class : defaultValue.getClass();
            return this.path2stream(path, (Object e) -> {
                if (e != null) { // 元素非空
                    if (uclass.isAssignableFrom(e.getClass())) { // 元素为U类型
                        var u = defaultValue;
                        try {
                            u = (U) e;
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }// try
                        return u;
                    } else {
                        return defaultValue;
                    }//if
                } else { // 元素为空
                    return defaultValue;
                }//if
            });// path2stream
        }
        
        /**
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return IRecord 类型的结果
         */
        default IRecord path2rec(final String path) {
            return this.path2rec(path,false);
        }
        
        /**
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param b 对于单值类型的数据v是否给予封装成 REC(0,v),<br>
         * 例如: 当 v 为3的时候 <br>
         * 如果b为true,3会被封装成 REC(0,3) 给予返回,<br>
         * 否则b为false，则返回 null
         * @return IRecord 类型的结果
         */
        default IRecord path2rec(final String path, final boolean b) {
            return getByPath(path, o -> {
                if (o == null) {
                    return null;
                } else if (o instanceof IRecord) {
                    return (IRecord) o;
                } else if (o instanceof Map) {
                    return REC((Map<?, ?>) o);
                } else {
                    var rec = b ? REC(0, o) : null;// 单值
                    final var jsn = o instanceof String ? o.toString() : Json.obj2json(o);
                    final var mode = Json.getJsonMode(jsn);
                    if (mode.equals(Json.JsonMode.MAP)) {
                        rec = REC("0", jsn).rec("0");// 类型转换
                    } // if
                    return rec;
                } // if
            });// if
        }
        
        /**
         * pathclc 的别名 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <T> 归集器元素类型
         * @param <U> 归集器结果类型
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param collector 归集器 [t]->u
         * @return U 类型的结果
         */
        default <T, U> U pathclc(final String path, final Collector<T, ?, U> collector) {
            return this.pathclc(path, (T) null, collector);
        }
        
        /**
         * pathS 的归集器版本 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <T> 归集器元素类型
         * @param <U> 归集器结果类型
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param defaultValue 默认值
         * @param collector 归集器 [t]->u
         * @return U 类型的结果
         */
        default <T, U> U pathclc(final String path, final T defaultValue, final Collector<T, ?, U> collector) {
            return this.pathS(path, defaultValue).collect(collector);
        }
        
        /**
         * pathS 的别名 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return Object 类型的流
         */
        default Stream<Object> pathS(final String path){
            return this.pathS(path, null);
        }
        
        /**
         * path2stream 的别名 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <U> 目标数据元素类型
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param defaultValue 元素的默认值
         * @return U 类型的流
         */
        default <U> Stream<U> pathS(final String path, final U defaultValue){
            return this.path2stream(path, defaultValue);
        }
        
        /**
         * path2stream 的别名 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <T> 源数据元素类型
         * @param <U> 目标数据元素类型
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param mapper 元素变换函数 t->u
         * @return U类型 的流
         */
        default <T,U> Stream<U> pathS(final String path,final Function<T,U> mapper) {
            return this.path2stream(path,mapper);
        }

        /**
         * pathL 的别名 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return Object 类型的列表
         */
        default List<Object> pathL(final String path){
            return this.pathL(path, null);
        }
        
        /**
         * path2stream 的列表形式衍生函数 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <U> 目标数据元素类型
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param defaultValue 元素的默认值
         * @return U 类型的 列表
         */
        default <U> List<U> pathL(final String path, final U defaultValue){
            return this.path2stream(path, defaultValue).collect(Collectors.toList());
        }
        
        /**
         * pathA 的别名 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return Object 类型的 数组
         */
        default Object[] pathA(final String path){
            return this.pathA(path, null);
        }
        
        /**
         * path2stream 的数组形式衍生函数 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <U> 目标数据元素类型
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param defaultValue 元素的默认值
         * @return U 类型的 数组
         */
        default <U> U[] pathA(final String path, final U defaultValue){
            return this.path2stream(path, defaultValue).collect(IRecord.aaclc(e->e));
        }
        
        /**
         * path2obj 的别名 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return Object 类型的结果
         */
        default Object pathO(final String path) {
            return this.path2obj(path);
        }
        
        /**
         * path2rec 的别名 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @return IRecord 类型的结果
         */
        default IRecord pathR(final String path) {
            return this.path2rec(path);
        }
        
        /**
         * path2rec 的别名 <br>
         * 根据路径获取Record 数据值。<br> 
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式  <br> 
         * 类似于如下的形式
         * [k0:[ <br>
         *   k1:[ <br>
         *   k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param path 键名序列,分隔符sep 默认为："[/]+"  键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param b 对于单值类型的数据v是否给予封装成 REC(0,v),<br>
         * 例如: 当 v 为3的时候 <br>
         * 如果b为true,3会被封装成 REC(0,3) 给予返回,<br>
         * 否则b为false，则返回 null
         * @return IRecord 类型的结果
         */
        default IRecord pathR(final String path,final boolean b) {
            return this.path2rec(path,b);
        }
        
        /**
         * path2rec 与 toTarget的联合函数 <br>
         * 相当于 : this.path2rec(path,true).toTarget(defaultVaue); <br>
         * 根据路径获取Record 数据值。<br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式 <br>
         * 类似于如下的形式 [k0:[ <br>
         * k1:[ <br>
         * k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <T>          结果类型
         * @param path         键名序列,分隔符sep 默认为："[/]+" 键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param defaultValue 默认值,转换失败或是结果为null的时候返回默认值
         * @return T类型的结果
         */
        default <T> T pathT(final String path,final T defaultValue) {
            return pathT(path,null,defaultValue);
        }
        
        /**
         * path2rec 与 toTarget的联合函数 <br>
         * 相当于 : this.path2rec(path,true).toTarget(defaultVaue); <br>
         * 根据路径获取Record 数据值。<br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式 <br>
         * 类似于如下的形式 [k0:[ <br>
         * k1:[ <br>
         * k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <T>          结果类型
         * @param path         键名序列,分隔符sep 默认为："[/]+" 键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param tclass       结果类型类
         * @return T类型的结果
         */
        default <T> T pathT(final String path,final Class<T> tclass) {
            return pathT(path,tclass,null);
        }
        
        /**
         * path2rec 与 toTarget的联合函数 <br>
         * 相当于 : this.path2rec(path,true).toTarget(defaultVaue); <br>
         * 根据路径获取Record 数据值。<br>
         * 这是对 递归结构(层级式)的 IRecord 按照 路径键名序列path 进行访问的算法,<br>
         * 即 IRecord的字段元素仍然是 IRecord的形式 <br>
         * 类似于如下的形式 [k0:[ <br>
         * k1:[ <br>
         * k2:value]]] <br>
         * getByPath("k0/k1/k2",identity) 返回 value 数值 <br>
         *
         * @param <T>          结果类型
         * @param path         键名序列,分隔符sep 默认为："[/]+" 键名序列 的分割符号，这样就可以从path中构造出层级关系。
         * @param tclass       结果类型类
         * @param defaultValue 默认值,转换失败或是结果为null的时候返回默认值
         * @return T类型的结果
         */
        @SuppressWarnings("unchecked")
        default <T> T pathT(final String path,final Class<T> tclass,final T defaultValue) {
            final var rec = this.path2rec(path, true);// 提取结果对象
            final var clazz = tclass == null 
                    ? (defaultValue == null ? null : (Class<T>) defaultValue.getClass())
                    : tclass;
            return rec == null ? defaultValue : rec.toTarget(clazz,defaultValue);
        }

        /**
         * 这里key 是一个集合对象List，用t2u的对集合List中的元素进行处理：<br>
         * 把一个列表改变成另一个列表，也就是在不改变聚合方式的情况下改变元素内容，这就是所谓的换药不换瓶 <br>
         * 如果value是一个List类型,Collection 这直接使用 序列转化，对于单元素的类型，这使用Arrays.asList 对其进行包装<br>
         * 给予扩展乘一个只有一个元素的List<br>
         * 不存在的key,不予处理返回null<br>
         * 
         * @param <T> 字段key所以对应的列表数据的元素的类型
         * @param <U> 字段key所以对应的列表数据的元素的类型T进行变换的结果
         * @param key 列表类型的字段名
         * @param t2u 对key字段的元素数据进行变换的结构
         * @return 以U类型为元素类型的列表结构,List 的复制品，注意不是元列表引用
         */
        @SuppressWarnings("unchecked")
        default <T, U> List<U> llapply(final String key, final Function<T, U> t2u){
            List<U> uu = null;
            try {
                List<T> tt = null; // T 类型的元素列表
                final Object o = get(key); // 提取key的值
                if(o==null)return null;// 不存在的value值不予处理返回null
                
                if(o instanceof List) {// List 类型
                    tt = new ArrayList<>((List<T>)o); // 复制一个李彪
                }else if(o instanceof ArrayNode) {// Jackson的节点元素类型
                    tt = new LinkedList<>(); // 复制列表
                    final ArrayNode anode = (ArrayNode)o;
                    final var itr = anode.iterator();
                    final var splitr = Spliterators.spliteratorUnknownSize(itr,Spliterator.ORDERED);
                    try {StreamSupport.stream(splitr,false).map(e->(T)e).forEach(tt::add);}
                    catch(Exception e){e.printStackTrace();}// 忽略异常
                }else if(o instanceof Collection){// Collection 类型
                    tt = new LinkedList<>(); // 复制列表
                    for(var t : ((Collection<?> )o))tt.add((T)t);
                }else if(o.getClass().isArray()) {// 数组类型
                    final var componetClazz = o.getClass().getComponentType();
                    if (componetClazz.isPrimitive()) { // 基础类型的处理
                        if (componetClazz == byte.class) {
                            final var aa = (byte[])o;
                            final var n = aa.length;
                            final var bb = new Byte[n];
                            for(int i=0;i<n;i++)bb[i]=aa[i];
                            tt = (List<T>)Arrays.asList(bb);
                        }else if (componetClazz == char.class) {
                            final var aa = (char[])o;
                            final var n = aa.length;
                            final var bb = new Character[n];
                            for(int i=0;i<n;i++)bb[i]=aa[i];
                            tt = (List<T>)Arrays.asList(bb);
                        } else if (componetClazz == boolean.class) {
                            final var aa = (boolean[])o;
                            final var n = aa.length;
                            final var bb = new Boolean[n];
                            for(int i=0;i<n;i++)bb[i]=aa[i];
                            tt = (List<T>)Arrays.asList(bb);
                        } else if (componetClazz == short.class) {
                            final var aa = (short[])o;
                            final var n = aa.length;
                            final var bb = new Short[n];
                            for(int i=0;i<n;i++)bb[i]=aa[i];
                            tt = (List<T>)Arrays.asList(bb);
                        } else if (componetClazz == int.class) {
                            final var aa = (int[])o;
                            final var n = aa.length;
                            final var bb = new Integer[n];
                            for(int i=0;i<n;i++)bb[i]=aa[i];
                            tt = (List<T>)Arrays.asList(bb);
                        } else if (componetClazz == long.class) {
                            final var aa = (long[])o;
                            final var n = aa.length;
                            final var bb = new Long[n];
                            for(int i=0;i<n;i++)bb[i]=aa[i];
                            tt = (List<T>)Arrays.asList(bb);
                        } else if (componetClazz == float.class) {
                            final var aa = (float[])o;
                            final var n = aa.length;
                            final var bb = new Float[n];
                            for(int i=0;i<n;i++)bb[i]=aa[i];
                            tt = (List<T>)Arrays.asList(bb);
                        } else if (componetClazz == double.class) {
                            final var aa = (double[])o;
                            final var n = aa.length;
                            final var bb = new Double[n];
                            for(int i=0;i<n;i++)bb[i]=aa[i];
                            tt = (List<T>)Arrays.asList(bb);
                        } else { // 非法的基础类型
                            System.err.println("未知的基础类型:"+componetClazz);
                        }
                    }else { // 非基础类型
                        tt = (List<T>)Arrays.asList((Object[])o); // 复制列表
                    }// if
                }else if(o instanceof IRecord) {// IRecord 类型
                    tt = (List<T>)((IRecord)o).values(); // 复制列表
                }else if(o instanceof Map) {// IRecord 类型
                    tt = (List<T>) new ArrayList<>(((Map<Object, Object>) o).values()); // 复制列表
                }else {// 其他 给予包装成一个List类型
                    tt = (List<T>) Collections.singletonList(o); // 复制列表
                }// 键值得类型判断与列表化构造
                
                if(tt!=null) {// 尝试进行类型转换
                    uu = tt.stream().map(t2u).collect(Collectors.toList()); // 复制列表
                }//if
                
            }catch(Exception e) {
                e.printStackTrace();
            }
            
            return uu;
        }
        
        /**
         * 这里key 是一个集合对象List，用t2u的对集合List中的元素进行处理：<br>
         * 把一个列表改变成另一个列表，也就是在不改变聚合方式的情况下改变元素内容，这就是所谓的换药不换瓶 <br>
         *
         * @param <T> 字段key所以对应的列表数据的元素的类型
         * @param <U> 字段key所以对应的列表数据的元素的类型T进行变换的结果
         * @param key 列表类型的字段名
         * @param uclass 列表元素类型
         * @return 以U类型为元素类型的列表结构
         */
        @SuppressWarnings("unchecked")
        default <T,U> List<U> lla(final String key, final Class<U> uclass){
            return llapply(key,u->(U)u);
        }
        
        /**
         * 这里key 是一个集合对象List，用t2u的对集合List中的元素进行处理：<br>
         * 把一个列表改变成另一个列表，也就是在不改变聚合方式的情况下改变元素内容，这就是所谓的换药不换瓶 <br>
         *
         * @param <T> 字段key所以对应的列表数据的元素的类型
         * @param <U> 字段key所以对应的列表数据的元素的类型T进行变换的结果
         * @param idx 列表类型的字段的索引号,从0开始
         * @param uclass 列表元素类型
         * @return 以U数元素类型的列表结构
         */
        @SuppressWarnings("unchecked")
        default <T,U> List<U> lla(final int idx, final Class<U> uclass){
            return llapply(idx,u->(U)u);
        }
        
        /**
         * 这里key 是一个集合对象List，用t2u的对集合List中的元素进行处理：<br>
         * 把一个列表改变成另一个列表，也就是在不改变聚合方式的情况下改变元素内容，这就是所谓的换药不换瓶 <br>
         *
         * @param <T> 字段key所以对应的列表数据的元素的类型
         * @param <U> 字段key所以对应的列表数据的元素的类型T进行变换的结果
         * @param key 列表类型的字段名
         * @param t2u 对key字段的元素数据进行变换的结构
         * @return 以U类型为元素类型的列表结构
         */
        default <T,U> List<U> lla(final String key, final Function<T, U> t2u){
            return llapply(key,t2u);
        }
        
        /**
         * 这里key 是一个集合对象List，用t2u的对集合List中的元素进行处理：<br>
         *   把一个列表改变成另一个列表，也就是在不改变聚合方式的情况下改变元素内容，这就是所谓的换药不换瓶 <br>
         *
         * @param <T> 字段key所以对应的列表数据的元素的类型
         * @param <U> 字段key所以对应的列表数据的元素的类型T进行变换的结果
         * @param idx 列表类型的字段的索引号从0开始
         * @param t2u 对key字段的元素数据进行变换的结构
         * @return 以U类型为元素类型的列表结构
         */
        default <T,U> List<U> lla(final int idx, final Function<T, U> t2u){
            return llapply(idx,t2u);
        }
        
        /**
         * 这里key 是一个集合对象List，用t2u的对集合List中的元素进行处理：<br>
         * 把一个列表改变成另一个列表，也就是在不改变聚合方式的情况下改变元素内容，这就是所谓的换药不换瓶 <br>
         *
         * @param <T> 字段key所以对应的列表数据的元素的类型
         * @param <U> 字段key所以对应的列表数据的元素的类型T进行变换的结果
         * @param idx 列表类型的字段的索引号从0开始
         * @param t2u 对key字段的元素数据进行变换的结构
         * @return 以U类型为元素类型的列表结构
         */
        default <T,U> List<U> llapply(final int idx, final Function<T, U> t2u){
            return llapply(idx2key(idx),t2u);
        }
        
        /**
         * 这里key 是一个集合对象List，用t2u的对集合List中的元素进行处理： <br>
         *   把一个列表改变成另一个列表，也就是在不改变聚合方式的情况下改变元素内容，这就是所谓的换药不换瓶 <br>
         *   T 为 objectNode 的特例 <br>
         * 
         * @param <T> 字段key所以对应的列表数据的元素的类型
         * @param <U> 字段key所以对应的列表数据的元素的类型T进行变换的结果
         * @param key 列表类型的字段名称
         * @param n2u 对key字段的元素数据进行变换的结构
         * @return 以U类型为元素类型的列表结构
         */
        default <T,U> List<U> nnapply(final String key, final Function<ObjectNode, U> n2u){
            return this.llapply(key, (ObjectNode o)->o).stream()
                .map(n2u).collect(Collectors.toList());
        }
        
        /**
         * 这里key 是一个集合对象List，用t2u的对集合List中的元素进行处理：<br>
         * 把一个列表改变成另一个列表，也就是在不改变聚合方式的情况下改变元素内容，这就是所谓的换药不换瓶<br>
         * T 为 objectNode 的特例<br> 
         * 
         * @param <U> 字段key所以对应的列表数据的元素的类型T进行变换的结果
         * @param idx 列表类型的字段的索引号从0开始
         * @param n2u 对key字段的元素数据进行变换的结构
         * @return 以U类型为元素类型的列表结构
         */
        default <T,U> List<U> nnapply(final int idx, final Function<ObjectNode, U> n2u){
            return this.llapply(idx2key(idx), (ObjectNode o)->o).stream()
                .map(n2u).collect(Collectors.toList());
        }
        
        /**
         * 这里key 是一个集合对象List，用t2u的对集合List中的元素进行处理：<br>
         * 把一个列表改变成另一个列表，也就是在不改变聚合方式的情况下改变元素内容，这就是所谓的换药不换瓶<br>
         * T 为 objectNode 的特例<br>
         *  
         * @param <U> 字段key所以对应的列表数据的元素的类型T进行变换的结果
         * @param key 列表类型的字段名称
         * @param n2u 对key字段的元素数据进行变换的结构
         * @return 以U数元素类型的列表结构
         */
        default <T,U> List<U> nna(final String key, final Function<ObjectNode, U> n2u){
            return nnapply(key,n2u);
        }
        
        /**
         * 这里key 是一个集合对象List，用t2u的对集合List中的元素进行处理：<br>
         * 把一个列表改变成另一个列表，也就是在不改变聚合方式的情况下改变元素内容，这就是所谓的换药不换瓶<br>
         * T 为 objectNode 的特例<br>
         *  
         * @param <U> 字段key所以对应的列表数据的元素的类型T进行变换的结果
         * @param idx 列表类型的字段的索引号从0开始
         * @param n2u 对key字段的元素数据进行变换的结构
         * @return 以U类型为元素类型的列表结构
         */
        default <T,U> List<U> nna(final int idx, final Function<ObjectNode, U> n2u){
            return nnapply(idx2key(idx),n2u);
        }
        
        /**
         * 是否含有指定索引的字段名．
         * @param idx 索引
         * @return 是否含有idx标号的索引
         */
        default boolean has(final int idx) {
            return this.get(idx2key(idx))==null;
        }
        
        /**
         * 字段的索引下标转字段名称
         * @param idx 索引序号从0开始
         * @return 索引对应的键名
         */
        default String idx2key(final Integer idx) {
            if(idx>=this.keys().size())return null;
            final String key = this.keys().get(idx);
            return key;
        }
        
        /**
         * 获取健民字段的索引号
         * @param key 键名
         * @return 键名索引
         */
        default Integer key2idx(final String key) {
            final var kk = this.keys().toArray(String[]::new);
            for(int i=0;i<kk.length;i++) {
                if(kk[i].equals(key))return i;
            }
            return null;
        }
        
        /**
         * 当且仅当key值不存在的才给予:compute,否则直接返回键值，属于名称来源于 Java Map <br>
         * compute 就是获取并变换设置。相当于 get&set: <br>
         * final var value = this.get(idx);<br>
         * if(value!=null)return (U)value; <br>
         * final var u = mapper.apply(idx);
         * this.set(key, u); <br>
         * 
         * @param <U> 变换的t2u的目标结果类型
         * @param idx 键名索引 从0开始
         * @param mapper key->U 类型的函数
         * @return 值变换后的数据。 U类型
         */
        @SuppressWarnings("unchecked")
        default <U> U computeIfAbsent(final Integer idx, final Function<Integer, U> mapper) {
            final var value = this.get(idx);
            if(value!=null)return (U)value;
            final var u = mapper.apply(idx);
            this.set(idx, u);
            return u;
        }

        /**
         * 当且仅当key值不存在的才给予:compute,否则直接返回键值，属于名称来源于 Java Map
         * compute 就是获取并变换设置。相当于 get&set: <br>
         * final var value = this.get(idx);<br>
         * if(value!=null)return (U)value; <br>
         * final var u = mapper.apply(key); <br>
         * set(key,u); <br>
         *  
         * @param <U> 变换的t2u的目标结果类型
         * @param key 字段键名
         * @param mapper key->U 类型的函数
         * @return 值变换后的数据。 U类型
         */
        @SuppressWarnings("unchecked")
        default <U> U computeIfAbsent(final String key, final Function<String, U> mapper){
            final var value = this.get(key);
            if(value!=null)return (U)value;
            final var u = mapper.apply(key);
            this.set(key, u);
            return u;
        }
        
        /**
         * 当且仅当key值不存在的才给予:compute,否则直接返回键值，属于名称来源于 Java Map <br>
         * compute 就是获取并变换设置。相当于 get&set: <br>
         * U u = mapper.apply(idx,get(key)) <br>
         * set(key,u); <br>
         * 
         * @param <T> 变换的t2u源数据类型
         * @param <U> 变换的t2u的目标结果类型
         * @param idx 键名索引 从0开始
         * @param mapper 二元函数(key,value)->u
         * @return 值变换后的数据。 U类型
         */
        default <T,U> U computeIfAbsent(final Integer idx, final BiFunction<Integer, T, U> mapper){
            @SuppressWarnings("unchecked")
            final var o = (U)this.get(this.idx2key(idx));
            if(o!=null)return o;
            @SuppressWarnings("unchecked")
            final U u = mapper.apply(idx,(T)o);
            this.set(idx, u);
            return u;
        }

        /**
         * 当且仅当key值不存在的才给予:compute,否则直接返回键值，属于名称来源于 Java Map <br>
         * compute 就是获取并变换设置。相当于 get&set: <br>
         * U u = mapper.apply(key,get(key,t2u)) <br>
         * set(key,u); <br>
         * 
         * @param <T> 变换的t2u源数据类型
         * @param <U> 变换的t2u的目标结果类型
         * @param key 键名
         * @param mapper 键值变换函数(key,value)->u
         * @return 值变换后的数据。 U类型
         */
        default <T,U> U computeIfAbsent(final String key, final BiFunction<String, T, U> mapper){
            @SuppressWarnings("unchecked")
            final var o = (U)this.get(key);
            if(o!=null)return o;
            @SuppressWarnings("unchecked")
            final U u = mapper.apply(key,(T)(Object)o);
            this.set(key, u);
            return u;
        }
        
        /**
         * 获取并变换设置。相当于 相当于 get&set: <br>
         * U u = get(key,t2u) <br>
         * set(key,u); <br>
         * 
         * @param <T> 变换的t2u源数据类型
         * @param <U> 变换的t2u的目标结果类型
         * @param idx 键名索引 从0开始
         * @param t2u 值变换函数 value0->value1
         * @return 值变换后的数据。
         */
        default <T,U> U compute(final Integer idx, final Function<T, U> t2u){
            final U u = this.get(idx, t2u);
            final var key = this.idx2key(idx);
            this.set(key, u);
            return u;
        }
        
        /**
         * 获取并变换设置。相当于 get&set: <br>
         * U u = get(key,t2u) <br>
         * set(key,u); <br>
         * 
         * @param <T> 变换的t2u源数据类型
         * @param <U> 变换的t2u的目标结果类型
         * @param key 键名
         * @param t2u 键值变换函数 value0->value1
         * @return 值变换后的数据。 U类型
         */
        default <T,U> U compute(final String key, final Function<T, U> t2u){
            final U u = this.get(key, t2u);
            this.set(key, u);
            return u;
        }

        /**
         * 获取并变换设置。相当于 相当于 get&set: <br>
         * U u = mapper.apply(key, (T)get(key)); <br>
         * set(key,u); <br>
         * 
         * @param <T> 变换的t2u源数据类型
         * @param <U> 变换的t2u的目标结果类型
         * @param idx 键名索引 从0开始
         * @param mapper 值变换函数 value0->value1
         * @return 值变换后的数据。
         */
        default <T,U> U compute(final Integer idx, final BiFunction<Integer, T, U> mapper){
            @SuppressWarnings("unchecked")
            final T t = (T)this.get(this.idx2key(idx));
            final U u = mapper.apply(idx,t);
            this.set(idx, u);
            return u;
        }
        
        /**
         * 当且晋档 key对应的值存在的时候才给予更新<br>
         * 相当于 调用 t2u 修改key所对应的值
         * @param <T> 变换的t2u源数据类型
         * @param <U> 变换的t2u的目标结果类型
         * @param key 键名
         * @param t2u 键值变换函数 value0->value1
         * @return 值变换后的数据。 U类型
         */
        default <T,U> U computeIfPresent(final String key, final Function<T, U> t2u){
            if(!this.has(key))return null;
            final U u = this.get(key, t2u);
            this.set(key, u);
            return u;
        }

        /**
         * 当且晋档 key对应的值存在的时候才给予更新<br>
         * 相当于 调用 t2u 修改索引idx所对应的值
         * @param <T> 变换的t2u源数据类型
         * @param <U> 变换的t2u的目标结果类型
         * @param idx 键名索引 从0开始
         * @param t2u 值变换函数 t->u
         * @return 值变换后的数据。
         */
        default <T,U> U computeIfPresent(final Integer idx, final Function<T, U> t2u){
            final var key = this.idx2key(idx);
            return computeIfPresent(key,t2u);
        }

        /**
         * k->t->u <br>
         * 获取并变换设置。相当于 相当于 get&set:  <br>
         * U u = mapper.apply(key, (T)get(key));  <br>
         * set(key,u);  <br>
         * 
         * @param <T> 变换的mapper源数据类型
         * @param <U> 变换的mapper额目标结果类型
         * @param key 键名
         * @param mapper 二元值变换函数  (key,value0)->value1
         * @return 值变换后的数据。
         */
        default <T,U> U compute(final String key, final BiFunction<String, T, U> mapper){
            @SuppressWarnings("unchecked")
            final T t = (T)this.get(key);
            final U u = mapper.apply(key,t);
            this.set(key, u);
            return u;
        }
        
        /**
         * 把自身 与 rec的kvs对象合并成一个对象
         * 
         * @param rec IRecord类型的 键值对儿集合：记录结构
         * @param append 是否追加到自身
         * @return 新合并后的对象 包含有 this,与 rec 的所有属性。
         */
        default IRecord union(final IRecord rec, boolean append) {
            return union(this,rec,append);
        }
        
        /**
         * 把rec中的数据值合并到自身。
         * @param rec 等待添加的record
         * @param overlap 同名键值是否用 rec来覆盖自身的值
         * @return 自身对象
         */
        default IRecord merge(final IRecord rec, final boolean overlap) {
            if(overlap)return union(this,rec,true);
            final var keys = new HashSet<>(this.keys());
            final var rec2 = rec.filter(e->!keys.contains(e.key()));
            if(rec2.size()<1)return this;
            return union(this,rec2,true);
        }
        
        /**
         * 把rec中的数据值合并到自身：不进行覆盖 
         * @param rec 等待添加的record
         * @return 自身对象
         */
        default IRecord merge(final IRecord rec) {
            return this.merge(rec,false);
        }
        
        /**
         * 把rec的所有在kvs值添加自身的kvs 之中，采用的是rec的add 方法。
         * @param rec 等待添加的record
         * @return 自身对象
         */
        default IRecord add(final IRecord rec) {
            return union(this,rec,true);
        }
        
        /**
         * 表头:所有字段名集合
         * @return 所有字段名集合列表
         */
        default List<String> keys(){
            return this.stream().map(Tuple2::_1).collect(Collectors.toList());
        }
        
        /**
         * 表头: 所有字段名集合 keys 的别名
         * @return 所有字段名集合列表
         */
        default List<String> kk(){
            return this.keys();
        }
        
        /**
         * 值元素集合的流
         * @param <T> 值类型
         * @param mapper 值映射对象方法
         * @return 值元素集合的流
         */
        default <T> Stream<T> valueS(final Function<Object, T> mapper){
            return this.stream().map(e->mapper.apply(e._2()));
        }
        
        /**
         * 值的流
         * @param <T> 值元素类型
         * @param tclazz 类型占位符用于 指定 T的具体类型
         * @return 值集合列表
         */
        @SuppressWarnings("unchecked")
        default <T> Stream<T> valueS(final Class<T> tclazz){
            return this.valueS(e->(T)e);
        }

        /**
         * 值集合
         * @param <T> 值类型
         * @param mapper 值映射对象方法
         * @return 所有值集合列表
         */
        default <T> List<T> values(final Function<Object, T> mapper){
            return this.valueS(mapper).collect(Collectors.toList());
        }
        
        /**
         * 值集合
         * @param <T> 值元素类型
         * @param tclazz 类型占位符用于 指定 T的具体类型
         * @return 值集合列表
         */
        @SuppressWarnings("unchecked")
        default <T> List<T> values(final Class<T> tclazz){
            return this.values(e->(T)e);
        }

        /**
         * 值集合
         * @return 值集合列表
         */
        default List<Object> values(){
            return this.values(identity);
        }
        
        /**
         * 值集合 (values 的别名)
         * @param <T> 值类型
         * @param mapper 值映射目标对象方法
         * @return 所有值集合列表
         */
        default <T> List<T> vv(final Function<Object, T> mapper){
            return this.values(mapper);
        }
        
        /**
         * 值集合
         * @return 所有值集合列表
         */
        default List<Object> vv(){
            return this.values();
        }
        
        /**
         * 值元素集合的流
         * @param <T> 值元素类型
         * @param tclazz 类型占位符用于 指定 T的具体类型
         * @return 值元素集合的流
         */
        @SuppressWarnings("unchecked")
        default <T> Stream<T> vS(final Class<T> tclazz){
            return this.valueS(e->(T)e);
        }
        
        /**
         * 转换成一个一维数组
         */
        default String[] toStringArray(){
            return this.stream().map(g->g._2()==null?"":g._2().toString()).toArray(String[]::new);
        }
        
        /**
         * 视键值对儿kvp的值为单值类型(非集合类型[比如List,Set,HashMap等]),比如 Integer,Long,Double 等，把当前集合中的值集合转换成 一维数组<br>
         * 转换成一个一维数组
         * @return Object 类型的一维数组
         */
        default Object[] toObjArray(){
            return this.stream().map(g->g._2()==null?"":g._2()).toArray(Object[]::new);
        }
        
        /**
         * 视键值对儿kvp的值为单值类型(非集合类型[比如List,Set,HashMap等]),比如 Integer,Long,Double 等，把当前集合中的值集合转换成 一维数组<br>
         * 转换成一维数组
         * @param <T> 源元素的类型
         * @param <U> 目标元素的类型
         * @param mapper 变换函数
         * @param uclass 目标结果类型：如果uclass 为null则懂mapper的取值结果中提取uclass 类型
         * @return U类型的一维数组
         */
        @SuppressWarnings("unchecked")
        default <T,U> U[] toArray(Function<T, U> mapper, final Class<U> uclass){
            Object[] oo = this.stream().map(e->(T)e._2()).map(mapper).toArray();
            Class<U> _uclass = uclass;
            if(uclass==null)for(Object o:oo) {
                if(o!=null) {
                    _uclass = (Class<U>)o.getClass();
                    break;
                }
            }//if
            if(_uclass==null)_uclass=(Class<U>)Object.class;
            U[] uu = (U[])Array.newInstance(_uclass, oo.length);
            for(int i=0;i<oo.length;i++) {
                try{uu[i]=(U)oo[i];}catch(Exception ignored) {};
            }
            return uu;
        }
        
        /**
         * 视键值对儿kvp的值为单值类型(非集合类型[比如List,Set,HashMap等]),比如 Integer,Long,Double 等，把当前集合中的值集合转换成 一维数组<br>
         * 转换成一维数组
         * @param <T> 源元素的类型
         * @param <U> 目标元素的类型
         * @param mapper 变换函数
         * @return U类型的一维数组
         */
        default <T,U> U[] toArray(Function<T, U> mapper){
            return toArray(mapper,(Class<U>)null);
        }
        
        /**
         * 视键值对儿kvp的值为单值类型(非集合类型[比如List,Set,HashMap等]),比如 Integer,Long,Double 等，把当前集合中的值集合转换成 一维数组<br>
         * @param <U> 目标元素的类型
         * @param uclass 结果的类型类，这是一个占位符类型，用于提示辅助编译。
         * @return U类型的一维数组
         */
        @SuppressWarnings("unchecked")
        default <U> U[] toArray(final Class<U> uclass){
            Object[] oo = this.toObjArray();
            Class<U> final_uclass = uclass==null?(Class<U>)Object.class:uclass;
            U[] uu = (U[])Array.newInstance(final_uclass, oo.length);
            for(int i=0;i<oo.length;i++) {
                try{uu[i]=(U)oo[i];}catch(Exception ignored) {};
            }
            return uu;
        }
        
        /**
         * 视键值对儿kvp的值为单值类型(非集合类型[比如List,Set,HashMap等]),比如 Integer,Long,Double 等，把当前集合中的值集合转换成 一维数组<br>
         * 转换成布尔值数组
         * @return 布尔类型的一维数组
         */
        default Boolean[] bools(){
           return this.toArray(Boolean.class);
        }
        
        /**
         * 把IRecord 视为一个 key-value的序列
         * 提取指定键值徐璐 拼装成一个键值列表
         * @return 返回的 IRecord 结构为  key:kkk,value:vvv
         */
        default List<IRecord> kvlist(){
            return kvlist((String[])null);
        }
        
        /**
         * 把IRecord 视为一个 key-value的序列
         * 提取指定键值徐璐 拼装成一个键值列表
         * @param keys 用逗号分割的键名序列
         * @return 返回的 IRecord 结构为  key:kkk,value:vvv
         */
        default List<IRecord> kvlist(final String keys){
            return LIST(kvstream(keys));
        }
        
        /**
         * 把IRecord 视为一个 key-value的序列
         * 提取指定键值徐璐 拼装成一个键值列表
         * @param keys 用逗号分割的键名序列
         * @return 返回的IRecord 结构为  key:kkk,value:vvv
         */
        default List<IRecord> kvlist(final String[] keys){
            return LIST(kvstream(keys));
        }
        
        /**
         * 把IRecord 视为一个(key,value) 键值对kvp而的序列,为 每个kvp构造一个IRecord(key:kkk,value:vvv)<br>
         * 然后再把这这种IRecord化的kvp给予流序列化。之所以采用IRecord来 转换KVP是为了利用IRecord缩影提供的方法。<br>
         * 着对于key,value是复杂数据类型的时候非常有用，例如：当key是一个路径的层级信息,value是一个操作语义的数据对象。kvstream 后<br>
         * 就会得到一个 (key:路径,value:对于集合) 的record. ("张三 /苹果",REC("name","卖","quality","5")) 就得到了<br>
         * 一个 张三够吗5个苹果的 数据指令。进而可以通过IRecord来提取这些数据内容。比如:<br>
         * REC("张三 /苹果",REC("name","卖","quality","5")).applyForKvs( IRecord::STRING2REC, e->(IRecord)e )<br>
         * 就可以得到一个 (IRecord,IRecord) 的数据Map，可以分方便的进行 数据分解。<br>
         * <br>
         * @return 返回的 IRecord 结构为  key:kkk,value:vvv，即一个 IRecord 格式的kv键值对儿记录流
         */
        default Stream<IRecord> kvstream(){
            return kvstream((String)null);
        }
        
        /**
         * 把IRecord 视为一个 key-value的序列
         * 提取指定键值徐璐 拼装成一个键值列表
         * @param keys 用逗号分割的键名序列:用于过滤返回的key,keys 为null不进行任何过滤，返回全部
         * @return 返回的 IRecord 结构为  key:kkk,value:vvv
         */
        default Stream<IRecord> kvstream(final String keys){
            final String kk[] = keys==null?null:keys.split("[\\s,]+");
            return this.filter(kk).stream().map(g->REC2("key",g._1(),"value",g._2()));
        }
        
        /**
         * 把IRecord 视为一个 key-value的序列
         * 提取指定键值徐璐 拼装成一个键值列表
         * @param keys 用逗号分割的键名序列:用于过滤返回的key,keys 为null不进行任何过滤，返回全部
         * @return 返回的 IRecord 结构为  key:kkk,value:vvv
         */
        default Stream<IRecord> kvstream(final String keys[]){
            return this.filter(keys).stream().map(g->REC2("key",g._1(),"value",g._2()));
        }

        /**
         * 生成一个 记录对象，不会对原来的对象进行更改操作
         * @param key 需要移除的键值名
         * @return 移除了指定key的字段序列
         */
        default IRecord remove(final String key) {
            return this.filter(kvp->!kvp.key().equals(key));
        }
        
        /**
         * 使用map 函数变换指定列的数据,以key 所在数值在作为参数调用mapper所指定的函数.
         *   
         * @param <T> 目标结果的类型
         * @param key 键名
         * @param mapper 键值映射函数
         * @return T类型的目标结果
         */
        default <T> T map(final String key, final Function<Object, T> mapper){
            return mapper.apply(this.get(key));}
        
        /**
         * 使用map 函数变换指定列的数据,以key 所在数值在作为参数调用mapper所指定的函数.
         * @param <T> t2u定义域类型
         * @param <U> t2u的值域类型
         * @param key 键名
         * @param t2u 键值映射函数
         * @return 以key 所在数值在作为参数调用mapper所指定的函数.
         */
        @SuppressWarnings("unchecked")
        default <T,U> U map2(final String key, final Function<T, U> t2u){
            T t = null;
            try{t = (T)this.get(key);}catch(Exception ignored) {};
            if(t==null)return null;
            return t2u.apply(t);
        }
        
        /**
         * 使用map 函数变换指定列的数据,以key 所在数值在作为参数调用mapper所指定的函数.
         *
         * @param <T> t2u定义域类型
         * @param <U> t2u的值域类型
         * @param idx 键名的索引序号从0开始
         * @param t2u 键值映射函数
         * @return 以key 所在数值在作为参数调用mapper所指定的函数.
         */
        @SuppressWarnings("unchecked")
        default <T,U> U map2(final int idx, final Function<T, U> t2u){
            T t = null;
            try{t = (T)this.get(idx);}catch(Exception ignored) {};
            if(t==null)return null;
            return t2u.apply(t);
        }
        
        
        /**
         * 强制类型转换，把key 作为T 类型数据
         * @param id 字段序号，从0开始
         * @return T 类型数据
         */
        @SuppressWarnings("unchecked")
        default <T> T as(final int id, final Class<T> tcls){
            return (T)(this.get(id));
        }
        
        /**
         * 强制类型转换，把key 作为iT 类型数据
         * @param key 字段名
         * @return T类型数据
         */
        @SuppressWarnings("unchecked")
        default <T> T as(final String key, final Class<T> tcls){
            return (T)(this.get(key));
        }
        
        /**
         * 把键key的视作一个 Function&lt;IRecord,IRecord &gt;
         * @param key 字段名
         * @return Function&lt;IRecord,IRecord &gt;
         */
        @SuppressWarnings("unchecked")
        default Function<IRecord,IRecord> fx(final String key){
            try {
                final var fx = (Function<IRecord,IRecord>)(this.get(key));
                return fx;
            }catch(Exception e) {
                return null;
            }
        }
        
        /**
         * 把键key的视作一个 BiFunction &lt;IRecord,IRecord,IRecord &gt;
         * @param key 字段名
         * @return  BiFunction &lt;IRecord,IRecord,IRecord &gt;
         */
        @SuppressWarnings("unchecked")
        default BiFunction<IRecord,IRecord,IRecord> fx2(final String key){
            try {
                final var fx2 = (BiFunction<IRecord,IRecord,IRecord>)(this.get(key));
                return fx2;
            }catch(Exception e) {
                return null;
            }
        }
        
        /**
         * 把键key的视作一个  Function &lt;List<IRecord>,IRecord &gt; 的函数
         * @param key 字段名
         * @return Function &lt;List<IRecord>,IRecord &gt;
         */
        @SuppressWarnings("unchecked")
        default Function<List<IRecord>,IRecord> fxx(final String key){
            try {
                final var fxx = (Function<List<IRecord>,IRecord>)(this.get(key));
                return fxx;
            }catch(Exception e) {
                return null;
            }
        }
        
        /**
         * 把键key的视作一个  BiFunction &lt;List &lt; IRecord &gt;, List &lt; IRecord &gt;,IRecord &gt,IRecord &gt;
         * @param key 字段名
         * @return BiFunction &lt;List &lt; IRecord &gt;,&lt; IRecord &gt;,IRecord &gt;
         */
        @SuppressWarnings("unchecked")
        default BiFunction<List<IRecord>,List<IRecord>,IRecord> fxx2(final String key){
            try {
                final var fxx2 = (BiFunction<List<IRecord>,List<IRecord>,IRecord> )(this.get(key));
                return fxx2;
            }catch(Exception e) {
                return null;
            }
        }
        
        /**
         * 需要注意：xx 的元素中的每个元素 都是一个独立的列向量，代表一个单独的属性维度。这一点非常重要。<br>
         * 二元函数的应用 <br>
         * 这是模仿tensorflow 的session.run 把当前IRecord 视作一个 ops 集合{key0,op0,key1:op1,key2:op2,...}<br>
         * 进行一个这样的运算:{key0:op0.apply(x,y),key1:op1.apply(x,y),key2:op2.apply(x,y)} <br>
         * 将fx视为一个二元函数列表：为每个二元函数 apply 参数 x,y并求职 <br>
         * 
         * @param x 输入参数  x
         * @param y 输入参数 y
         * @return IRecord
         */
        default IRecord fapply(IRecord x, IRecord y){
            return aov2rec((BiFunction<IRecord,IRecord,IRecord> f)->f.apply(x,y));
        }

        /**
         * 需要注意：xx 的元素中的每个元素 都是一个独立的列向量，代表一个单独的属性维度。这一点非常重要。<br>
         * 多元函数的应用 <br>
         * 将本实例元素视为 一个  多元函数 fxx:[x0,x1,x2,...]->y <br>
         * List &lt; IRecord &gt; 是列向量构成的数据矩阵 xx:{col0,col2,col2,...} . 把 xx 视做一个 [r0,r1,r2,...] 的行向量的实参集合。 <br>
         * 把每个行向量应用到 fxx: fxx.apply(r0) ->y0, fxx.apply(r0) ->y1, fxx.apply(r0) ->y2, ... <br>
         * 并最终 将 (y0,y1,y2,...) 拼接成一个列向量  result:REC(0,y0,1,y1,2,y2). 并将 result 返回。 <br>
         * 
         * @param xx 输入多参数向量
         * @return fxx 应用之后的 列向量IRecord 
         */
        default IRecord fapply(List<IRecord> xx){
            return aov2rec((Function<List<IRecord>,IRecord> f)->f.apply(xx));
        }
        
        /**
         * 需要注意：xx 的元素中的每个元素 都是一个独立的列向量，代表一个单独的属性维度。这一点非常重要。<br>
         * 多元函数的应用 <br>
         * 将本实例元素视为 一个  多元函数 fxx:[x0,x1,x2,...]->y <br>
         * List &lt; IRecord &gt; 是列向量构成的数据矩阵 xx:{col0,col2,col2,...} . 把 xx 视做一个 [r0,r1,r2,...] 的行向量的实参集合。 <br>
         * 把每个行向量应用到 fxx: fxx.apply(r0) ->y0, fxx.apply(r0) ->y1, fxx.apply(r0) ->y2, ... <br>
         * 并最终 将 (y0,y1,y2,...) 拼接成一个列向量  result:REC(0,y0,1,y1,2,y2). 并将 result 返回。 <br>
         * 
         * @param xx 参数1
         * @param yy 参数2
         * @return fxx 应用之后的 列向量IRecord 
         */
        default IRecord fapply(final List<IRecord> xx, final List<IRecord> yy){
            return aov2rec((BiFunction<List<IRecord>,List<IRecord>,IRecord> f)->f.apply(xx,yy));
        }

        /**
         * 视IRecord为函数集:<br>
         * 用key0的函数 f  去 组合 (compose ) key1的函数 g,获得一个 f.compose(g)的函数 即：<br>
         * this.fx(key0).compose(this.fx(key1));<br>
         * @param key0 字段名0
         * @param key1 字段名1
         * @return Function&lt;IRecord,IRecord &gt;
         */
        default Function<IRecord,IRecord> compose(final String key0, String key1){
            return this.fx(key0).compose(this.fx(key1));
        }

        /**
         * 视IRecord为函数集:<br>
         * 每个key标识一个函数fx:(rec0,rec1)->rec <br>
         * 从键名序列key0,key1提取出函数对儿 (fx0,fx1),对于 函数对儿(fx0,fx1)应用输入对儿(rec00,rec01）<br>
         * 获得输出值对儿(rec10,rec11),fx0(rec01,rec02)对应rec10,fx1(rec01,rec02)对应rec11,
         * 合在一起就构成了(rec10,rec11),然后对输出值对儿(rec10,rec11)应用gx获取[rec20,rec21]
         * 即生成一个:(rec00,rec01）->[fx:key1,key2] ->gx->[rec20,rec21]的函数 <br>
         * @param gx 复合函数
         * @param key0 字段名0
         * @param key1 字段名1
         * @return Function&lt;IRecord,IRecord &gt;
         */
        default BiFunction<IRecord,IRecord,IRecord> compose(final BiFunction<IRecord, IRecord, IRecord> gx, final String key0, final String key1){
            return (x,y)->gx.apply(this.fx2(key0).apply(x, y), this.fx2(key1).apply(x, y));
        }

        /**
         * 视IRecord为函数集:<br>
         * 每个key标识一个函数fx:[rec0]->rec1 <br>
         * 从键名序列keys 提取出函数列表[fx],对于[fx] 应用输入列表[rec0] 获得输出列表[rec1],<br>
         * 一个fx对应一个rec1,合在一起就构成了[rec1]<br>
         * 然后对[rec1]应用gx.<br>
         * 即生成一个:[rec0]->[fx:keys]->gx->[rec1] 的函数 <br>
         * @param gx 复合函数
         * @param keys 字段名称序列
         * @return Function&lt;IRecord,IRecord &gt;
         */
        default Function<List<IRecord>,IRecord> compose(final Function<List<IRecord>, IRecord> gx, final String... keys){
            
            return (xx)->gx.apply(Stream.of(keys).map(this::fxx)
                .filter(Objects::nonNull).map(f->f.apply(xx)).collect(Collectors.toList()));
        }

        /**
         * 检索满足条件所有键值对儿
         * @param predicate 字段名
         * @return 满足 predicate 条件的键值对儿
         */
        default List<KVPair<String,Object>> find(final Predicate<KVPair<String, Object>> predicate){
           if(predicate==null)return null;
           return this.kvs().stream().filter(predicate).collect(Collectors.toList());
        }
        
        
        /**
         * 检索满足条件的第一个键值对儿
         * @param predicate 字段名
         * @return 满足 predicate 条件的键值对儿
         */
        default Optional<KVPair<String,Object>> findOne(final Predicate<KVPair<String, Object>> predicate){
            if(predicate==null)return Optional.empty();
            return this.kvs().stream().filter(predicate).findFirst();
        }
        
        /**
         * 检索值类型为clazz 类型的对象。检索成功返回该值，不成功 null
         * @param <T> 检索的目标对象的类型
         * @param clazz 目标值的类型
         * @return 检索成功返回该值，不成功 null
         */
        @SuppressWarnings("unchecked")
        default <T> T findOne(Class<T> clazz){
          final var opt = this.kvs().stream().filter(e->e.value()!=null &&
                clazz.isAssignableFrom(e.value().getClass())).findFirst();
            return opt.map(stringObjectKVPair -> (T) stringObjectKVPair.value()).orElse(null);
        }
        
        /**
         * 检索值类型为clazz 类型的对象。检索成功返回该值，不成功 null, 并对 T类型的结果调用 mapper给予变换 <br>
         * @param <T> 检索的目标对象的类型
         * @param <U> 变换结果
         * @param clazz 目标值的类型
         * @param mapper T->U 的变换函数
         * @return 检索成功返回该值，不成功 null
         */
        default <T,U> U findOne2(Class<T> clazz, Function<T, U> mapper){
          final T t = this.findOne(clazz);
          return mapper.apply(t);
        }
        
        /**
         * 强制类型转换，把key 作为T 类型数据,转换成函数,一般用于lambda表达式提取
         * @param key 字段名
         * @return Function类型的对象
         */
        @SuppressWarnings("rawtypes")
        default Function func(final String key){
            return as(key,Function.class);
        }
        
        /**
         * 普通函数求职<br>
         * 强制类型转换，把key 作为T 类型数据,转换成函数,一般用于lambda表达式提取<br>
         * 
         * @param <T> 函数的参数类型
         * @param <U> 函数返回值类型
         * @param key 字段名, key 业与一个(Function<T,U> t2u 绑定。
         * @param arg 字段名, 提交各key:t2u 函数的 参数对象
         * @return 调用与key绑定的t2u.apply(arg)
         */
        @SuppressWarnings("unchecked")
        default <T,U> U eval(final String key, final T arg){
            Function<T,U> foo = ((Function<T,U>)as(key,Function.class));
            if(foo==null)return null;
            U u = foo.apply(arg);
            return u;
        }
        
        /**
         * 强制类型转换，把key 作为T 类型数据,转换成函数,一般用于lambda表达式提取
         * 
         * @param <FUNC> 函数类型
         * @param <U> 目标结果类型
         * @param key key 字段名, key 业与一个(Function<T,U> t2u 绑定。
         * @param functorClass 函数类
         * @param args 函数的实际参数
         * @return 调用与key绑定的t2u.apply(arg)
         */
        @SuppressWarnings("unchecked")
        default <FUNC,U> U eval2(final String key, final Class<FUNC> functorClass, final Object... args){
            FUNC func = as(key,functorClass);
            if(ANNO(functorClass,FunctionalInterface.class)==null) {
                System.out.println(functorClass+" 需要时一个函数接口，必须强制用@FunctionalInterface标记！");
                return null;
            }// if 
            final var method = functorClass.getMethods()[0];
            U obj = null;// 返回值
            try {
                obj = (U)method.invoke(func, args);
            } catch (Exception e) {
                e.printStackTrace();
            }// try
            return obj;
        }
        
        /**
         * 强制类型转换，把key 作为iT 类型数据,转换成函数,一般用于lambda表达式提取
         * @param key 字段名
         * @param args 回调函数的参数
         */
        @SuppressWarnings("unchecked")
        default <T> void callback(final String key, final T args){
            Consumer<T> foo = as(key,Consumer.class);
            if(foo==null)return;
            foo.accept(args);
        }
        
        /**
         * 强制类型转换，<br>
         * 一般用于lambda表达式类型的值<br>
         * 把key 作为T->U类型函数:t2u<br>
         * 返回一个 应用了 arg:T的结果u:U类型 ,t2u.apply(arg)<br>
         * <br>
         * @param <T> t2u即key值 的参数的类型
         * @param <U> t2u即key值 的结果类型
         * @param key 字段名 即 t2u的函数的键名
         * @param arg t2u的具体参数
         * @param ucls 返回的结果类型类,这是一个类型占位符,用于向编译器提供类型信息，并无实际运算意义。
         * @return U类型数据
         */
        @SuppressWarnings("unchecked")
        default <T,U> U evaluate(final String key, final T arg, final Class<U> ucls){
            final Function<T,U> foo = ((Function<T,U>)as(key,Function.class));
            if(foo==null)return null;
            final U u = foo.apply(arg);
            return u;
        }
        
        /**
         * 强制类型转换，<br>
         * 一般用于lambda表达式类型的值<br>
         * 把key 作为T->U类型函数:t2u<br>
         * 返回一个 应用了 arg:T的结果u:U类型 ,t2u.apply(arg)<br>
         * <br>
         * @param <T> t2u即key值 的参数的类型
         * @param <U> t2u即key值 的结果类型
         * @param key 字段名 即 t2u的函数的键名
         * @param arg t2u的具体参数
         * @param obj 结果类型U的对象载体,其实就一为了方便提供 Class<U>的类型提取,null表示Object类型
         * @return U类型数据
         */
        @SuppressWarnings("unchecked")
        default <T,U> U evaluate(final String key, final T arg, final U obj){
            if(obj==null)return eval(key,arg);
            return this.evaluate(key, arg, (Class<U>) (obj == null ? Object.class : obj.getClass()));
        }
        
        /**
         * 表达式求职：这里是模仿 R语言的 eviroment的设计的方法。
         * 把key作为变量名执行一段javascript程序,变量名采用#开头的变量名。<br>
         * "#{1}([a-z_][a-zA-z0-9_]*)" <br>
         * 示例：<br>
         * System.out.println(REC("a",3,"b",4).evalExpr("Math.pow(#a,2)+Math.pow(#b,2)"));<br>
         * evaluate 会寻找内建的ExpressionEvaluator来进行表达式计算。
         * @param expr javascript 的脚本文件
         * @param varpattern 变量的模式结构,默认为 IRecord.SHARP_VARIABLE 
         * @param elu 表达式计算引擎
         * @return javascript 程序的执行结果 :浮点数的数值
         */
        default Double evalExpr(final String expr, final String varpattern, final ExpressionEvaluator elu){
            final ExpressionEvaluator _elu = elu ==null ?this.findOne(ExpressionEvaluator.class) :elu; // 计算环境中的计算器
            final var evaluator = _elu != null  ?_elu :new ExpressionEvaluator() ; // 计算环境没有计算器 则自动创建一个。
            final var var_pattern = Pattern.compile(varpattern==null
                ? IRecord.SHARP_VARIABLE_PATTERN // 默认的变量模式
                : varpattern);// 变量的模式
            // 表达式计算
            final var line = substitute(expr,var_pattern,this);// 变量补充。
            final var value = line==null ?null :evaluator.eval2dbl(line);// 计算表达式的值
            
            return value;
        }
        
        /**
         * 把key作为变量名执行一段javascript程序,变量名采用#开头的变量名。<br>
         * "#{1}([a-z_][a-zA-z0-9_]*)" <br>
         * 示例：<br>
         * System.out.println(REC("a",3,"b",4).evalExpr("Math.pow(#a,2)+Math.pow(#b,2)"));<br>
         * evaluate 会寻找内建的ExpressionEvaluator来进行表达式计算。
         * @param expr javascript 的脚本文件
         * @param varpattern 变量的模式结构,默认为 IRecord.SHARP_VARIABLE  
         * @return javascript 程序的执行结果 :浮点数的数值
         */
         default Double evalExpr(final String expr, final String varpattern){
            return evalExpr(expr,varpattern,null);
         }
        
         /**
          * 把key作为变量名执行一段javascript程序,变量名采用#开头的变量名。<br>
          * "#{1}([a-z_][a-zA-z0-9_]*)" <br>
          * 示例：<br>
          * System.out.println(REC("a",3,"b",4).evalExpr("Math.pow(#a,2)+Math.pow(#b,2)"));<br>
          * evaluate 会寻找内建的ExpressionEvaluator来进行表达式计算。
          * @param expr javascript 的脚本文件  
          * @return javascript 程序的执行结果 :浮点数的数值
          */
         default Double evalExpr(final String expr) {
             return evalExpr(expr,(String)null);
         }
         
         /**
          * 把key作为变量名执行一段javascript程序,变量名采用#开头的变量名。<br>
          * "#{1}([a-z_][a-zA-z0-9_]*)" <br>
          * 示例：<br>
          * System.out.println(REC("a",3,"b",4).evalExpr("Math.pow(#a,2)+Math.pow(#b,2)"));<br>
          * evaluate 会寻找内建的ExpressionEvaluator来进行表达式计算。
          * @param expr javascript 的脚本文件 
          * @param context expr中的变量所存放的上下文 
          * @return javascript 程序的执行结果 :浮点数的数值
          */
         default Double evalExpr(final String expr, final IRecord context) {
             final var rec = this.duplicate().add(context);
             return rec.evalExpr(expr,(String)null);
         }
        
        /**
         * 强制类型转换，把key 作为T 类型数据,转换成函数,一般用于lambda表达式提取
         * @param key 字段名
         * @return IRecord 结果的数据
         */
       default <T,U> IRecord bind(final String key, final Function<T, U> transform, final String newKey){
            U obj =  this.eval(key, transform);
            return REC(newKey==null?key:newKey,obj);
        }
       
       /**
        * 强制类型转换，把key 作为 T 类型数据,转换成函数,一般用于lambda表达式提取
        * @param transform 变换函数
        * @return bind 结果的数据
        */
        @SuppressWarnings("unchecked")
        default <T, U> IRecord bind(final Function<T, U> transform) {
            final IRecord rec = REC();
            Function<T, U> foo = t -> {
                U u = null;
                try {
                    u = transform.apply(t);
                } catch (Exception ex) {
                    // ex.printStackTrace();
                } // try
                return u;
            };

            this.kvs().stream().map(e -> new Tuple2<>(e._1(), foo.apply((T) get(e._1())))).forEach(kv -> {
                if (kv._2 != null)
                    rec.add(kv._1, kv._2);
            });
            return rec;
        }
        
        /**
         * Record 搜集器:这个方法是为了放置编译器抱怨ambiguous错误
         * 
         * @param <R> 规约结果的类型
         * @param supplier 容器:()->r0
         * @param accumulator 累加:(r0,kv)->r1
         * @param combiner 和兵器:(r1,r2)->r3
         * @return 规约的结果 R
         */
        default <R> R collect0(final Supplier<R> supplier,final BiConsumer<R, KVPair<String, Object>> accumulator,
                final BinaryOperator<R> combiner) {
            
            final var collector = Collector.of(supplier,accumulator, combiner);
            return  this.stream().collect(collector);
        };
        
        /**
         * Record 搜集器:这个方法是为了放置编译器抱怨ambiguous错误<br>
         * 默认 combiner 为:(a,b)->a
         * 
         * @param <R> 规约结果的类型
         * @param supplier 容器:()->r0
         * @param accumulator 累加:可以带有一个返回值，这个返回值会被忽略掉:(r0,kv)->r1
         * @return 规约的结果 R
         */
        default <R> R collect(final Supplier<R> supplier,final BiConsumer<R, KVPair<String, Object>> accumulator) {
            return this.collect0(supplier, accumulator, (a,b)->a);
        };
        
        /**
         * Record 搜集器
         * 
         * @param <R> 规约结果的类型
         * @param supplier 容器:()->r0
         * @param accumulator 累加:(r0,kv)->r1
         * @param combiner 合并器:(r1,r2)->r3
         * @return 规约的结果 R
         */
        default <R> R collect(final Supplier<R> supplier,
                final BiConsumer<R, KVPair<String, Object>> accumulator,final BinaryOperator<R> combiner) {
            return this.collect0(supplier, accumulator, combiner);
        };
        
        /**
         * Record 搜集器
         * 
         * @param <R> 结果的类型
         * @param initial 初始值:r0
         * @param accumulator 累加器:(r0,kv)->r1
         * @param combiner 合并器:(r1,r2)->r3
         * @return 规约的结果 R
         */
        default <R> R collect(final R initial,
                final BiConsumer<AtomicReference<R>, KVPair<String, Object>> accumulator,
                final BinaryOperator<R> combiner) {
            
            final var collector = Collector.of(()-> new AtomicReference<>(initial),accumulator,
                (aa,bb)-> new AtomicReference<>(combiner.apply(aa.get(), bb.get())));
            return  this.stream().collect(collector).get();
        };
        
        /**
         * Record 搜集器
         * @param <A> 累加器的元素 类型 中间结果类型,用于暂时存放 累加元素的中间结果的集合。
         * @param <R> 返回结果类型
         * @param collector 搜集 KVPair&lt;String,Object&gt;类型的 搜集器
         * @return 规约的结果 R
         */
        default <A,R> R collect(final Collector<KVPair<String, Object>, A, R> collector) {
            return this.stream().collect(collector);
        };
        
        /**
         * DFrame 函数 <br>
         * Row collect <br>
         * 把IRecord视为一个DataFrame dfm,而后 把dfm转换成个一个行流，最后使用 collector进行归集。<br>
         * @param <R> 结果类型
         * @param collector 行归集器
         * @return R类型的结果
         */
        default <R> R rcollect(final Collector<IRecord, List<IRecord>, R> collector) {
            return IRecord.ROWSCLC(collector).apply(this);
        }

        /**
         * DFrame 函数 (rcollect2 的后缀2表示这是一个队KVPair 进行归集的版本） <br>
         * Row KVPair 的 collect <br>
         * 把IRecord视为一个DataFrame dfm,而后 把dfm转换成个一个行流KVPair用key_idx,value_idx标定键名与键值，最后使用 collector进行归集。<br>
         * @param key_idx key 索引 从0开始
         * @param value_idx  value 索引从0开始
         * @param collector 行归集器
         * @return R类型的结果
         */
        default <R> R rcollect2(final int key_idx,final int value_idx,final Collector<KVPair<String,?>,List<KVPair<String,Object>>,R> collector) {
            return this.rows2().map(e->KVP(e.str(key_idx),e.get(value_idx))).collect(collector);
        }

        /**
         * DFrame 函数 (rcollect2 的后缀2表示这是一个队KVPair 进行归集的版本） <br>
         * Row KVPair 的 collect <br>
         * 把IRecord视为一个DataFrame dfm,而后 把dfm转换成个一个行流KVPair用key_name,value_name标定键名与键值，最后使用 collector进行归集。<br>
         * @param key_name key 键名
         * @param value_name  value 键名
         * @param collector 行归集器
         * @return R类型的结果
         */
        default <R> R rcollect2(final String key_name,final String value_name,final Collector<KVPair<String,?>,List<KVPair<String,Object>>,R> collector) {
            return this.rows2().map(e->KVP(e.str(key_name),e.get(value_name))).collect(collector);
        }

        /**
         * DFrame 函数 (rcollect2 的后缀2表示这是一个队KVPair 进行归集的版本）<br>
         * Row KVPair 的 collect <br>
         * 把把IRecord视为一个DataFrame dfm,而后 把dfm转换成个一个行流KVPair用0,1标定键名与键值，最后使用 collector进行归集。<br>
         *  rcollect（0,1,collector)的别名函数
         * @param collector 行归集器
         * @return R类型的结果
         */
        default <R> R rcollect2(final Collector<KVPair<String,?>,List<KVPair<String,Object>>,R> collector) {
            return this.rcollect2(0,1,collector);
        }
        
       /**
        * 把KV值规约到一个数值R
        * 
        * @param <R> 规约结果的类型
        * @param kv2r KV值转换成R类型数据。kv->r
        * @param initial 初始值:r0
        * @param reducer 规约算法:(r0,r1)->r2 
        * @return 规约的结果 R
        */
        default <R> R reduce(final Function<KVPair<String, ?>, R> kv2r, final R initial,
                             final BinaryOperator<R> reducer) {
            final Collector<KVPair<String,Object>,AtomicReference<R>,AtomicReference<R>> collector = 
                Collector.of(()-> new AtomicReference<>(initial),
                (aa,b)-> aa.set(reducer.apply(aa.get(),kv2r.apply(b))),
                (aa,bb)-> new AtomicReference<>(reducer.apply(aa.get(), bb.get())));
            return  this.stream().collect(collector).get();
        };
            
        /**
         * 左折叠
         * @param <R> 规约结果的类型
         * @param initial 初始值:r0
         * @param op 折叠函数 (r0,kv)->r1
         * @return R 的累计结果
         */
        default <R> R foldLeft(final R initial, final BiFunction<R, KVPair<String, ?>, R> op) {
            var ar = new AtomicReference<>(initial);
            this.stream().forEach(kv -> ar.set(op.apply(ar.get(), kv)));
            return ar.get();
        };
        
        /**
         * 把键值对儿中的值数据 用 delim 进行串联：
         * [0:1    1:2 2:3 3:4] 的返回结果是: 1/2/3/4
         * @param delim 分隔符
         * @return delim 分割的values序列
         */
        default String vvjoin(String delim) {
           return this.foldLeft((String)null,(r,kv)->MFT("{0}{1}{2}",r==null?"":r,r==null?"":delim,kv._2()));
        };
        
        /**
         * 把键值对儿中的值数据 用 delim 进行串联：
         * [0:1    1:2 2:3 3:4] 的返回结果是: 1/2/3/4
         * delim 分隔符 默认为 ：“/”
         * @return delim 分割的values序列
         */
        default String vvjoin() {
           final var delim = "/";
           return this.foldLeft((String)null,(r,kv)->MFT("{0}{1}{2}",r==null?"":r,r==null?"":delim,kv._2()));
        };
         
        /**
         * 右折叠
         * 
         * @param <R> 规约结果的类型
         * @param initial 初始值:r0
         * @param op 折叠函数 ：(kv,r0)->r1
         * @return 右折叠的累计结果
         */
        default <R> R foldRight(R initial, final BiFunction<KVPair<String, ?>, R, R> op) {
            final var ar = new AtomicReference<>(initial);
            final var kvs = this.kvs();
            final var reverse_litr = kvs.listIterator(kvs.size());// 移动到列表末尾
            while (reverse_litr.hasPrevious()) ar.set(op.apply(reverse_litr.previous(),ar.get()));
            return ar.get();
        };
        
        /**
         * 把KV值规约到一个整型
         *
         * @param initial 初始值:r0
         * @param reducer 规约算法:(r0,r1)->r2 
         * @return 规约的结果
         */
         default Integer reduce(final Integer initial,
                                BinaryOperator<Integer> reducer) {
             return this.reduce(kv2int, initial, reducer);
         }
         
         /**
         * 把KV值规约到一个数值:Double 类型
         *
         * @param initial 初始值:r0
         * @param reducer 规约算法:(r0,r1)->r2
         * @return 规约的结果
         */
         default Double reduce(final Double initial,
                               final BinaryOperator<Double> reducer) {
             return this.reduce(kv2dbl, initial, reducer);
         }
         
         /**
         * 把KV值规约到一个数值R:Long 类型
         *
         * @param initial 初始值:r0
         * @param reducer 规约算法:(r0,r1)->r2 
         * @return 规约的结果
         */
         default Long reduce(final Long initial,
                             final BinaryOperator<Long> reducer) {
             return this.reduce(kv2lng, initial, reducer);
         }
         
         /**
          * 数据窗口滑动：step 每次移动的步长为1<br>
          * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
          * 
          * | size | 每个窗口大小为 size,每次移动的步长为step<br>
          * [1    2]<br>
          * step0:[2    3]<br>
          *   - step1:[3    4]<br>
          *   -   -   step2:[4]<br>
          * 返回:[  [1,2],  [2,3],  [3,4],  [4] ]<br>
          * 
          * @param size 滑动的窗口大小
          * @return 滑动窗口的列表。
          */
         default List<List<KVPair<String,Object>>> sliding(final int size) {
             return sliding(this.kvs(),size,1);
         }
         
         /**
          * slidingStream
          * 数据窗口滑动：step 每次移动的步长为1<br>
          * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
          * 
          * | size | 每个窗口大小为 size,每次移动的步长为step<br>
          * [1    2]<br>
          * step0:[2    3]<br>
          *   - step1:[3    4]<br>
          *   -   -   step2:[4]<br>
          * 返回:[  [1,2],  [2,3],  [3,4],  [4] ]<br>
          * 
          * @param size 滑动的窗口大小
          * @return 滑动窗口的Stream<List<KVPair<String,Object>>>
          */
         default Stream<List<KVPair<String,Object>>> sliding2(final int size) {
             return sliding(this.kvs(),size,1).stream();
         }
         
         /**
          * tup2Stream
          * 分解成一个窗口长度为2的收尾向量的线段:线段空间。
          * 数据窗口滑动：step 每次移动的步长为1<br>
          * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
          * 
          * | size | 每个窗口大小为 size,每次移动的步长为step<br>
          * [1    2]<br>
          * step0:[2    3]<br>
          *   - step1:[3    4]<br>
          *   -   -   step2:[4]<br>
          * 返回:[  [1,2],  [2,3],  [3,4] ] 对结果进行截取没有 [4,null]节点 <br>
          * 
          * @return 滑动窗口的Stream<List<KVPair<String,Object>>>
          */
         default Stream<Tuple2<KVPair<String,Object>,KVPair<String,Object>>> tuple2Stream() {
            return this.tuple2Stream(true);
         }
         
         /**
          * tup2Stream
          * 分解成一个窗口长度为2的收尾向量的线段:线段空间。
          * 数据窗口滑动：step 每次移动的步长为1<br>
          * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
          * 
          * | size | 每个窗口大小为 size,每次移动的步长为step<br>
          * [1    2]<br>
          * step0:[2    3]<br>
          *   - step1:[3    4]<br>
          *   -   -   step2:[4]<br>
          * 返回:[  [1,2],  [2,3],  [3,4],  [4] ]<br>
          * 
          * @param discardSinglePoint 是否版单点元素给剔除, 比如对于 [ [1,2],  [2,3],  [3,4],  [4] ] <br>
          * true: 只返回 [  [1,2],  [2,3],  [3,4]]  <br>
          * false: 将返回[  [1,2],  [2,3],  [3,4],[4,null]] <br>
          * @return 滑动窗口的Stream<List<KVPair<String,Object>>>
          */
         default Stream<Tuple2<KVPair<String,Object>,KVPair<String,Object>>> tuple2Stream(boolean discardSinglePoint) {
             return sliding(this.kvs(),2,1).stream().filter(e-> !discardSinglePoint || e.size() == 2)
                 .map(e->TUP2(e.get(0),e.size()>1?e.get(1):null));
         }
         
         /**
          * 数据窗口滑动<br>
          * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
          * 
          * | size | 每个窗口大小为 size,每次移动的步长为step<br>
          * [1    2]<br>
          * step0:[2    3]<br>
          *   - step1:[3    4]<br>
          *   -   -   step2:[4]<br>
          * 返回:[  [1,2],  [2,3],  [3,4],  [4] ]<br>
          * 
          * @param size 滑动的窗口大小
          * @param step 每次移动的步长
          * @return 滑动窗口的列表。
          */
         default List<List<KVPair<String,Object>>> sliding(final int size, final int step) {
             return sliding(this.kvs(),size,step);
         }
         
         /**
          * 数据窗口滑动<br>
          * 对一个:1 2 3 4,5按照 size:为2,step为1的参数进行滑动的结果。<br>
          * 
          * | size | 每个窗口大小为 size,每次移动的步长为step<br>
          * [1    2]<br>
          * step0:[2    3]<br>
          *   - step1:[3    4]<br>
          *   -   -   step2:[4]<br>
          * 返回:[  U1,  U2,  U3,  U4 ]<br>
          * mapper.apply([1,2])==U1
          * mapper.apply([2,3])==U2
          * 
          * @param <U> 元素类型
          * @param size 滑动的窗口大小
          * @param step 每次移动的步长
          * @param mapper 窗口变换函数
          * @return 滑动窗口的列表。
          */
         default <U> Stream<U> sliding2(final int size, final int step,
                                        final Function<List<KVPair<String, Object>>, U> mapper) {
             
             return sliding(this.kvs(),size,step).stream().map(mapper);
         }
         
        /**
         * 使用map 函数变换指定列的数据
         * @param mapper 变换函数
         * @param <T> mapper 的转换类型
         * @return map 函数变换指定列的数据
         */
        default <T> T map(final int idx, final Function<Object, T> mapper){
            String key = this.idx2key(idx);return key==null?null:map(key,mapper);
        }

        /**
         * 把key列转换成字符串
         * @param key 键名
         * @return 字符串数据
         */
        default String str(final String key){
            return map(key,o->o==null?null:o.toString());
        }

        /**
         * 把key列转换成浮点数
         * @param key 键名
         * @return 字符串类型
         */
        default String str(final String key, final String default_value){
            final var ret = this.str(key);
            return ret == null?default_value:ret;
        }

        /**
         * 把key列转换成字符串
         * @param idx 从0开始
         * @return 字符串
         */
        default String str(final int idx){
            String key = this.idx2key(idx);return key==null?null:str(key);
        }

        /**
         * 把key列转换成浮点数
         * @param idx 索引编号 从0开始
         * @return 字符串类型
         */
        default String str(final int idx, final String default_value){
            final var ret = this.str(idx);
            return ret == null?default_value:ret;
        }

        /**
         * 把key列转换成字符串
         * @param key 键名
         * @return 短整型
         */
        default Short i2(final String key){
            final var num = this.num(key);
            return num==null?null:num.shortValue();
        }
        
        /**
         * 把key列转换成字符串
         * @param key 键名
         * @return 短整型
         */
        default Short i2(final String key, final short default_value){
            final var num = this.num(key);
            return num==null?default_value:num.shortValue();
        }

        /**
         * 把key列转换成字符串
         * @param index 从0开始
         * @return 短整型
         */
        default Short i2(final int index){
            final var num = this.num(index);
            return num==null?null:num.shortValue();
        }
        
        /**
         * 把key列转换成字符串
         * @param index 从0开始
         * @return 短整型
         */
        default Short i2(final int index, final short default_value){
            final var num = this.num(index);
            return num==null?default_value:num.shortValue();
        }

        /**
         * 把key列转换成浮点数
         * @param key 键名
         * @return Double 双精度浮点数
         */
        default Double dbl(final String key){
            final var num = this.num(key);
            return num==null?null:num.doubleValue();
        }

        /**
         * 把key列转换成浮点数
         * @param key 键名
         * @return Double 双精度浮点数
         */
        default Double dbl(final String key, final Double default_value){
            final var ret = this.dbl(key);
            return ret == null?default_value:ret;
        }

        /**
         * 把key列转换成浮点数
         * @param idx 键名索引从0开始
         * @return 双精度浮点数
         */
        default Double dbl(final int idx) {
            String key = this.idx2key(idx);
            return key==null?null:dbl(key);
        }
        
        /**
         * 把key列转换成浮点数
         * @param idx 键名索引 从0开始
         * @param default_value 默认值
         * @return Double 双精度浮点数
         */
        default Double dbl(final int idx, final Double default_value){
            final var ret = this.dbl(idx);
            return ret == null?default_value:ret;
        }
        
        /**
         * 用法示例： System.out.println(REC("0","1.1234").i4(0)); --> 1 <br>
         * System.out.println(REC("0",".1234").i4(0)); -->0 <br>
         * System.out.println(REC("0","1.1234").dbl(0)); -->1.1234 <br>
         * System.out.println(REC("0","00.1234").dbl(0)); -->0.1234 <br>
         * System.out.println(REC("0","0.0.1234").dbl(0)); -->null <br>
         * 
         * 把key列的值转换成数字，除了数字以外其中： 字符串："true","fasle" 会被分别被转换成 1和0； bool型： true,fasle <br>
         * 会被分别被转换成 1和0 <br>
         * 
         * @param key 键名
         * @return 整数值
         */
        default Integer i4(final String key) {
            final var num = this.num(key);// 转换成数字
            return num == null?null:num.intValue();
        }
            
        /**
         * 把key列的值转换成数字，除了数字以外其中：
         *    字符串："true","fasle" 会被分别被转换成 1和0；
         *    bool型： true,fasle 会被分别被转换成 1和0
         * @param key 键名
         * @return Integer 整数值
         */
        default Integer i4(final String key, Integer default_value) {
            final var ret = this.i4(key);
            return ret==null?default_value:ret;
        }
            
        /**
         * 把key列转换成浮点数
         * @param idx 键名索引 从0开始
         * @return Integer 整数值
         */
        default Integer i4(final int idx) {
            String key = this.idx2key(idx);
            return key==null?null:i4(key);
        };

        /**
         *  把key列的值转换成数字，除了数字以外其中：
         *  字符串："true","fasle" 会被分别被转换成 1和0；
         *  bool型： true,fasle 会被分别被转换成 1和0
         * @param idx 键名 的索引号,从0开始
         * @return Integer 整数值
         */
        default Integer i4(final int idx, Integer default_value) {
            final var ret = this.i4(idx);
            return ret==null?default_value:ret;
        }
        
        /**
         * 把key列转换成数字
         * @param key 键名
         * @return 长整型
         */
        default Long lng(final String key){
            return map(key,o->{ Long lng=null; // 返回结果
                if(o instanceof Number) return((Number)o).longValue();
                try {lng=Long.parseLong(o+"");}catch(Exception e){
                    try{lng = ((Number)Double.parseDouble(o+"")).longValue();}
                    catch(Exception ignored) {} // try
                }// try
                return lng;
            });
        };
        
        /**
         * 把key列转换成数字
         * @param key 键名
         * @param default_value 默认值
         * @return 长整型
         */
        default Long lng(final String key, Long default_value){
            final var value = this.lng(key);
            return value==null?default_value:value;
        }
            
        /**
         * 把key列转换成浮点数
         * @param idx 键名索引 从0开始
         * @return 长整型
         */
        default Long lng(final int idx) {
            String key = this.idx2key(idx);
            return key==null?null:lng(key);
        };
        
        /**
         * 把idx列索引所标识的键名列值转换成数字
         * @param idx 键名索引 从0开始
         * @param default_value 默认值
         * @return 长整型
         */
        default Long lng(final int idx, Long default_value){
            final var value = this.lng(idx);
            return value==null?default_value:value;
        }

        /**
         * 把key字段转换成数字<br>
         * 布尔类型的值:false 转换成 0, true 转换成1
         * @param key 键名
         * @return 数值类型
         */
        default Number num(final String key){
            return map(key,o->{ 
                
                if(o instanceof Number) return((Number)o);// 数字值提取
                if(o instanceof Date) return(Number)((Date)o).getTime();// 日期转数字,java.sql.timestamp 是 Date的子类
                if(o instanceof LocalDate) return(Number)(CronTime.ld2dt((LocalDate)o)).getTime();// 日期转数字
                if(o instanceof LocalDateTime) return(Number)(CronTime.ldt2dt((LocalDateTime)o)).getTime();// 日期转数字
                if(o instanceof LocalTime) return(Number)(CronTime.lt2dt((LocalTime)o)).getTime();// 日期转数字
                if(o instanceof Boolean) return ((Boolean)o)?1:0;
                
                Double dbl=null;
                try {dbl=Double.parseDouble(o+"");}catch(Exception ignored){} // 默认使用Double进行数据解析
                
                return dbl;
            });// map
        };
            
        /**
         * 把key字段转换成数字
         * @param key 键名
         * @param default_value 默认值
         * @return Number
         */
        default Number num(final String key, Number default_value){
            final var ret = this.num(key);
            return ret==null?default_value:ret;
        };
        
        /**
         * 把key字段转换成数字
         * @param idx 键名索引 从0开始
         * @return 可能返回空值
         */
        default Number num(final int idx) {
            String key = this.idx2key(idx);
            return key==null?null:num(key);
        };

        /**
         * 把key字段转换成数字
         * @param idx 键名索引，从0开始
         * @param default_value 默认值
         * @return Number
         */
        default Number num(final int idx, Number default_value){
            final var ret = this.num(idx);
            return ret==null?default_value:ret;
        };
        
        /**
         * 把key字段转换成 异常对象
         * @param key 键名
         * @return 例外异常
         */
        default Exception except(final String key){return map(key, o->{
            if(o instanceof Exception) return((Exception)o);// 数字值提取
            else return null;});}
        
        /**
         * 把key字段转换成 异常对象
         * @param idx 键名索引 从0开始
         * @return 例外异常
         */
        default Exception except(final int idx) {
            String key = this.idx2key(idx);
            return key==null?null:except(key);
        };
        
        /**
         * 把key列转换成逻是时间值
         * @param key 键名
         * @return  Timestamp 时间错
         */
        default Timestamp timestamp(final String key){
            return map(key,o->{
               if(o==null)return null;
               if(o instanceof Timestamp) return (Timestamp)o;
               final var time = this.date(key);
               if(time==null)return null;
               return new Timestamp(time.getTime());
            });
        };
        
        /**
         * 把key列转换成逻是时间值
         * @param key 键名
         * @param default_value 默认值 
         * @return Timestamp
         */
        default Timestamp timestamp(final String key, Timestamp default_value) {
            return key==null?default_value:timestamp(key);
        };
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 键名索引 从0开始
         * @return Timestamp
         */
        default Timestamp timestamp(final int idx) {
            String key = this.idx2key(idx);
            return key==null?null:timestamp(key);
        };
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 键名索引 从0开始
         * @param default_value 默认值 
         * @return Timestamp
         */
        default Timestamp timestamp(final int idx, Timestamp default_value) {
            String key = this.idx2key(idx);
            return key==null?default_value:timestamp(key);
        };

        /**
         * 把key列转换成逻是时间值
         * @param key 键名
         * @return LocalDateTime
         */
        default LocalDateTime ldt(final String key){
            Object obj = this.get(key);
            if(obj==null)return null;
            if(obj instanceof LocalDateTime) return (LocalDateTime) obj;
            return CronTime.date2localDateTime(this.date(key));
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param key 键名
         * @param default_value 默认值,当 值为null时候返回
         * @return LocalDateTime
         */
        default LocalDateTime ldt(final String key, LocalDateTime default_value){
            final var ret = this.ldt(key);
            return ret == null?default_value:ret;
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 从0开始
         * @return LocalDateTime
         */
        default LocalDateTime ldt(final int idx){
            return CronTime.dt2ldt(this.date(idx2key(idx)));
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 从0开始
         * @param default_value 默认值,当 值为null时候返回
         * @return LocalDateTime
         */
        default LocalDateTime ldt(final int idx, LocalDateTime default_value){
            final var ret = this.ldt(idx);
            return ret == null?default_value:ret;
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param key 键名
         * @return LocalDate
         */
        default LocalDate ld(final String key){
            final Object obj = this.get(key);
            if(obj==null)return null;
            if(obj instanceof LocalDate) return (LocalDate) obj;
            return CronTime.dt2ld(this.date(key));
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param key 键名
         * @param default_value 默认值,当 值为null时候返回
         * @return LocalDate
         */
        default LocalDate ld(final String key, LocalDate default_value){
            final var ret = ld(key);
            return ret==null?default_value:ret;
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 从0开始
         * @return LocalDate
         */
        default LocalDate ld(final int idx){
            final Object obj = this.get(idx);
            if(obj==null)return null;
            if(obj instanceof LocalDate) return (LocalDate) obj;
            return CronTime.dt2ld(this.date(idx));
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 从0开始
         * @param default_value 默认值,当 值为null时候返回
         * @return LocalDate
         */
        default LocalDate ld(final int idx, LocalDate default_value){
            final var ret = ld(idx);
            return ret==null?default_value:ret;
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param key 键名
         * @return LocalTime
         */
        default LocalTime lt(final String key){
            final Object obj = this.get(key);
            if(obj==null)return null;
            if(obj instanceof LocalTime) return (LocalTime) obj;
            return CronTime.dt2lt(this.date(key));
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param key 键名
         * @param default_value 默认值,当 值为null时候返回
         * @return LocalTime
         */
        default LocalTime lt(final String key, LocalTime default_value){
            final var ret = lt(key);
            return ret==null?default_value:ret;
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 索引需要从0开始
         * @return LocalTime
         */
        default LocalTime lt(final int idx) {
            final Object obj = this.get(idx);
            if(obj==null)return null;
            if(obj instanceof LocalTime) return (LocalTime) obj;
            return CronTime.dt2lt(this.date(idx));
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 索引需要从0开始
         * @param default_value 默认值,当 值为null时候返回
         * @return LocalTime
         */
        default LocalTime lt(final int idx, LocalTime default_value) {
            final var ret = lt(idx);
            return ret==null?default_value:ret;
        }
        
        /**
         * 把key列转换成时间值,时间值转换成long
         * @param key 键名
         * @return long 时间值
         */
        default Long lngdate(final String key) {
            final Date date = date(key);
            if(date == null)return null;
            return date.getTime();
        }
        
        /**
         * 时间值<br>
         * 把key列转换成时间值<br>
         * 对于 数字类型的字符串，将给予解析成长整形后转换成日期<br>
         * @param key 键名
         * @return Date 日期类型
         */
        default Date date(final String key){
             return map(key,o->{
                Date date = null;
                if(o instanceof Date)return (Date)o;
                if(o instanceof LocalDateTime)return CronTime.ldt2dt((LocalDateTime)o);
                if(o instanceof LocalDate)return CronTime.ld2dt((LocalDate)o);
                if(o instanceof Timestamp) date = new Date(((Timestamp)o).getTime());
                else if (o instanceof Number || o instanceof LongNode){
                    final var lng =  o instanceof LongNode
                        ? ((LongNode)o).asLong()
                        : (Long)(((Number)o).longValue());
                    date = new Date(lng);}
                else if (o instanceof String || o instanceof TextNode ){
                    var value =o instanceof TextNode 
                        ? ((TextNode)o).asText()
                        : o.toString();
                    if(value.matches("[\\.\\d]+")) {// 数字类型的字符串
                        Number num = null;// 数字类型
                        try {
                            num = Double.parseDouble(value);// 尝试给予解析成数字
                        }catch(Exception e) {
                            // do nothing
                        }
                        if(num!=null)return new Date(num.longValue());
                    }
                    
                    // 需要注意顺序很重要"yyyy-MM-dd"，yyMMdd" 很重要,不能把yyMMdd放在首位
                    if(value.endsWith("Z")) {//解析带有时区的字符串．这个很丑陋，但是我也没有更好的办法,专门为mongo日期准备的解析
                        final var s = "yyyy-MM-dd'T'HH:mm:ss.SSS Z";
                        value = value.replace("Z", " UTC");
                        try{
                            date = new SimpleDateFormat(s).parse(value);// 时间解析
                            return date; 
                        }catch(Exception xx) {
                            // do nothing
                        }// try
                    }//if
                    
                    final var ss = new String[] {"yyMMdd","yyyyMMdd","yy-MM-dd","yyyy-MM-dd",
                        "yyyy-MM-dd HH","yyyy/MM/dd HH","yyyy-MM-dd HH:mm","yyyy/MM/dd HH:mm",
                        "yyyyMMdd HH:mm:ss","yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss",
                    };// 常用的时间格式
                    final var dates = new LinkedList<Date>();
                    for(String s:ss) {
                        try {date = new SimpleDateFormat(s).parse(value);} catch (Exception ignored) {}
                        if(date!=null) {
                            dates.add(date);
                        }else {
                            // do nothing
                        }// if if(date!=null) 
                    }//for s:ss
                    if(dates.size()>0)date = dates.getLast();//挑选出一个时间格式
                }//if
                
                return date;
            });// map
        };
        
        /**
         * 时间值<br>
         * 把key列转换成时间值<br>
         * 对于 数字类型的字符串，将给予解析成长整形后转换成日期<br>
         * @param key 键名
         * @param default_value 默认值
         * @return Date 日期类型
         */
        default Date date(final String key, final Date default_value) {
            final var dt = this.date(key);
            return dt == null? default_value:dt;
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 索引序号从０开始
         * @return 日期类型
         */
        default Date date(final int idx) {
            final String key = this.idx2key(idx);
            return key==null?null:date(key);
        };
        
        /**
         * 把key列转换成逻是时间值<br>
         * 对于 数字类型的字符串，将给予解析成长整形后转换成日期<br>
         * @param idx 索引序号从０开始
         * @param default_value 默认值
         * @return 日期类型
         */
        default Date date(final int idx, final Date default_value) {
            final var dt = this.date(idx);
            return dt == null? default_value:dt;
        };

        /**
         * 把key列转换成逻辑值
         * @param key 键名
         * @return 布尔类型
         */
        default Boolean bool(final String key){
            return map(key,o->Boolean.parseBoolean(o+""));
        };
        
        /**
         * 把key列转换成逻辑值
         * @param key 键名
         * @param default_value 默认值
         * @return 布尔类型
         */
        default Boolean bool(final String key, final Boolean default_value){
            final var b = this.bool(key);
            return b == null?default_value:b;
        };
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 键名索引从0开始
         * @return Boolean 类型
         */
        default Boolean bool(final int idx) {
            String key = this.idx2key(idx);
            return key==null?null:bool(key);
        };
        
        /**
         * 把key列转换成逻辑值
         * @param index 键名索引从0开始
         * @param default_value 默认值
         * @return 布尔类型
         */
        default Boolean bool(final int index, final Boolean default_value){
            final var b = this.bool(index);
            return b == null?default_value:b;
        };

        /**
         * 把列转换成指定的 类型，这里只是强制转换，没有完成值结构的变换。
         * @param <T> 目标类型
         * @param key 键/字段名称
         * @param cls 指定类型
         * @return T类型的返回值
         */
        @SuppressWarnings("unchecked")
        default <T> T val(final String key, final Class<T> cls){
            return (T)this.get(key);
        };//获取接口值
        
        /**
         * 把key列转换成逻是时间值
         * @param <T> 目标类型
         * @param idx 从0开始
         * @return T类型
         */
        default <T> T val(final int idx, final Class<T> cls) {
            final String key = this.idx2key(idx);
            return key==null?null:val(key,cls);
        };


        /**
         * 转换成一个 转义映射 '\' 被转译成  \\ "'" 被转译成   \'
         * @return 转移后的Map
         */
        default Map<String,Object> toEscapedMap(){
            final var m = this.toMap();
            m.forEach((k,v)->{// 依次对每个MAP元素进行转义
                m.put(k,v==null?null:v instanceof String
                ? v.toString() .replace("\"", "\\\\\"").replace("'","\\'")
                : v);// m.put
            });// forEach
            
            return m;
        };

        /**
         * 转换成一个json对象
         * @return 字符串形式的json对象
         */
        default String json(){
            return Json.obj2json(this.toEscapedMap());
        }
        
        /**
         * 强制类型转换方法 不保证安全  <br>
         * 把当前record(key-value)的值拼装成一个对象列表{obj0,obj1,obj2,...} <br>
         * 空值 null 被视作 "" <br>
         * @return {obj0,obj1,obj2,...}
         */
        default List<Object> oo(){
            return Arrays.asList(this.toObjArray());
        }
        
        /**
         * 强制类型转换方法 不保证安全 <br>
         * 把当前record的key的值转装成一个对象列表{obj0,obj1,obj2,...} <br>
         * @param key 字段名
         * @return {obj0,obj1,obj2,...}
         */
        default List<Object> oo(final String key){
            return llapply(key,identity);
        }
        
        /**
         * 强制类型转换方法 不保证安全
         * 把当前record的key的值转装成一个对象列表{obj0,obj1,obj2,...}
         * @param key 字段名
         * @param default_value 默认值：当key不存在的时候
         * @return {obj0,obj1,obj2,...}
         */
        default List<Object> oo(final String key, final List<Object> default_value){
            final var oo = llapply(key,identity);
            return oo==null?default_value:oo;
        }
        
        /**
         * 强制类型转换方法 不保证安全 <br>
         * 把当前record{(k0,v0),(k1,v1),(k2,v2)}的 值集合 拼装成一个字符串列表{v0,v1,v2,...} <br>
         * 空值 null 被视作 "" <br>
         * @return {v0,v1,v2,...}
         */
        default List<String> ss(){
            return Arrays.stream(this.toObjArray()).map(e->e+"").collect(Collectors.toList());
        }

        /**
         * 强制类型转换方法 不保证安全 <br>
         * 把当前record{(k0,v0),(k1,v1),(k2,v2)}的 值集合 拼装成一个字符串列表{v0,v1,v2,...} <br>
         * 空值 null 被视作 "" <br>
         * @param key 字段名 <br>
         * @return {str0,str1,str2,...}
         */
        default List<String> ss(final String key){
            return llapply(key,identity(String.class));
        }
        
        /**
         * 强制类型转换方法 不保证安全 <br>
         * 把当前record{(k0,v0),(k1,v1),(k2,v2)}的 值集合 拼装成一个字符串列表{v0,v1,v2,...} <br>
         * 空值 null 被视作 "" <br>
         * @param key 字段名
         * @param default_value 默认值：当key不存在的时候
         * @return {str0,str1,str2,...}
         */
        default List<String> ss(final String key, final List<String> default_value){
            final var ss = llapply(key,identity(String.class));
            return ss == null?default_value:ss;
        }
        
         /**
         * 强制类型转换方法 不保证安全 <br>
         * 把当前record的key的值转装成一个字符串啊列表{rec0,rec1,rec2,...} <br>
         * @param key 字段名
         * @return {rec0,rec1,rec2,...}
         */
        default List<IRecord> rr(final String key){
            return llapply(key,identity(IRecord.class));
        }
        
         /**
         * 强制类型转换方法 不保证安全 <br>
         * 把当前record的key的值转装成一个字符串啊列表{rec0,rec1,rec2,...}<br>
         * @param key 字段名
         * @param default_value 默认值：当key不存在的时候
         * @return {rec0,rec1,rec2,...}
         */
        default List<IRecord> rr(final String key, final List<IRecord> default_value){
            final var rr =  llapply(key,identity(IRecord.class));
            return rr==null?default_value:rr;
        }

        /**
         * 把key列转换成Map结构 <br>
         * 当且仅当 key 所代表的数据是一个Map<String,Object> 的实例返回一个 key 的value对象。<br>
         * 否则 生成一个 Map的复制品(clone) <br>
         *
         * @param key 需要进行分解的字段名：一般为json结构的列
         * @return Map<String, Object>
         */
        @SuppressWarnings("unchecked")
        default Map<String,Object> asMap(final String key) {
            final Object obj = this.get(key);
            if (obj == null) {
                return null;
            } else if (obj instanceof Map) { // Map类型
                final var mm = (Map<Object, Object>) obj;
                if (mm.keySet().iterator().next() instanceof String) { // key 为String类型
                    return (Map<String, Object>) obj;// Map 的key是不含null值的
                } else { // key 为非String类型
                    final var mss = new LinkedHashMap<String, Object>();// 复制品
                    mm.forEach((k, v) -> mss.put(k.toString(), v));// 进行数据复制。
                    return mss;
                } // if
            } else if (obj instanceof IRecord) { // IRecord 结构
                return ((IRecord) obj).toMap();
            } else { // 其他类型视为json 字符串给予转换映射
                return map(key, e -> Json.json2obj(e, Map.class));
            } // if
        }

        /**
         * 把idx列转换成Map结构
         *
         * @param idx 列索引从0开始
         * @return Map<String, Object>
         */
        default  Map<String,Object> asMap(final int idx) {
            final String key = this.idx2key(idx);
            return key==null?null:asMap(key);
        };
        
        /**
         * 整体转换<br>
         * 把REC 转传成 tclass类型的对象,采用OBJINIT初始化对象<br>
         * 注意与toTaget(部分转换)进行区分(toTarget 一般用于提取元素的第一个键值元素。只有当第一个元素不满足要求，才尝试采用cast的方式进行整体转换。)
         * @param <T> 目标对象类型
         * @param tclass 目标类型
         * @return T 类型的对象
         */
        default <T> T cast(final Class<T> tclass) {
            return cast(tclass,null);
        }
        
        /**
         * 整体转换<br>
         * 把REC 转传成 tclass类型的对象,采用OBJINIT初始化对象<br>
         * 注意与toTaget(部分转换)进行区分(toTarget 一般用于提取元素的第一个键值元素。只有当第一个元素不满足要求，才尝试采用cast的方式进行整体转换。)
         * @param <T> 目标对象类型
         * @param tclass 目标类型
         * @param init 对象的初始值
         * @return T 类型的对象
         */
        default <T> T cast(Class<T> tclass, T init) {
            T t =null;
            if(tclass==null)return null;
            try {
                t = tclass.getDeclaredConstructor((Class<?>[])null).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            if(init==null)init = t;
            return OBJINIT(init,this.toMap());
        }
        
        /**
         * 修改列名：根据具体实现类的不同 同名的key 可能会被覆盖。如果需要用重名的key请tagkvs序列
         * @param keymapper 改名
         * @return IRecord
         */
        default  IRecord keymap(final Function<String, String> keymapper) {
            return REC(toMap2(keymapper,identity));
        };
        
        /**
         * 依据索引值对kvs 进行标记
         * @param key2tag 改名函数：把键名改成指定的标号
         * @return SimpleRecord 的Record 可以存在多个同名的键名。即tag
         */
        default  IRecord tagkvs(final Function<String, String> key2tag) {
            final var rec = new SimpleRecord();
            
            this.kvs().forEach(kv->{
                final var key = key2tag.apply(kv.key());
                final var value = kv.value();
                rec.add(key,value);
            });
            
            return rec;
        };
        
        /**
         * 依据索引值对kvs 进行标记
         * @param idx2tag 改名函数
         * @return SimpleRecord
         */
        default  IRecord tagkvs_i(final Function<Integer, String> idx2tag) {
            final var rec = new SimpleRecord();
            final var ai = new AtomicInteger(0);
            
            this.kvs().forEach(kv->{
                final var key = idx2tag.apply(ai.getAndIncrement());
                rec.add(key,kv.value());
            });
            
            return rec;
        };
        
        /**
         * 修改列名:keymap 的别名，调整映射位置 project
         * @param keyname_mapper 改名函数
         * @return 修改了键名之后的IRecord
         */
        default  IRecord proj(final Function<String, String> keyname_mapper) {
            return keymap(keyname_mapper);
        };
        
        /**
         *  对值集合进行Map,不对key 进行变换
         * 把函数mapper 应用到  values 对象:Object->U 对象。
         * 转换成一个 String -> U 的Map
         * @param <U> valuemapper 对值的变换结果
         * @param valuemapper 值变换函数
         * @return {(String,U)} 结构的Map
         */
        default <U> LinkedHashMap<String,U> toMap(final Function<Object, U> valuemapper) {
            final LinkedHashMap<String,U> mm = new LinkedHashMap<>();
            this.toMap().forEach((k,v)->mm.put(k, valuemapper.apply(v)));
            return mm;
        }

        /**
         * 对键名集合进行Map,不对value 进行变换
         * @param <T> key 的类型
         * @param keymapper 键名变换函数:把原来的字符类型的key,转换成T类型的键名。
         * @return 键名变换后键值对儿({T ,Object)}
         */
        default  <T> LinkedHashMap<T,Object> toMap2(final Function<String, T> keymapper) {
            return toMap2(keymapper,identity);
        };

        /**
         * 分别对keys 和 values 进行变换。
         * 
         * @param <T> key 的类型
         * @param <U> value 的类型
         * @param keymapper key 键名变换函数:把原来的字符类型的key,转换成T类型的键名。
         * @param valuemapper value 的变换函数:把原来的Object类型的Value,转换成U类型的值。
         * @return {(t, u)} 的Map
         */
        default  <T,U> LinkedHashMap<T,U> toMap2(final Function<String, T> keymapper, Function<Object, U> valuemapper) {
            final LinkedHashMap<T,U> mm = new LinkedHashMap<>();
            this.foreach((k,v)-> mm.put(keymapper.apply(k),valuemapper.apply(v)));
            return mm;
        }
        
        /**
         * 字符串格式化
         * @param cell_formatter 键值得格式化算法
         * @return IRecord 的字符串形式
         */
        default String toString(final Function<Object, String> cell_formatter) {
            final var builder = new StringBuilder();
            final Function<Object,String> final_cell_formatter = cell_formatter!=null
            ?   cell_formatter
            :   v->{
                    if(v==null) return"(null)";
                    var line = "{0}";// 数据格式化
                    if(v instanceof Date) {
                        line = "{0,Date,yyyy-MM-dd HH:mm:ss}"; // 时间格式化
                    }else if(v instanceof Number) {
                        line = "{0,Number,#}"; // 数字格式化
                    }//if
                    return MessageFormat.format(line, v);
                };// cell_formatter
            
            this.kvs().forEach(p-> builder.append(p._1()).append(":").append(final_cell_formatter.apply(p._2())).append("\t"));
            
            return builder.toString().trim();
        }
        
        /**
         * 返回一个 LinkedHashMap<String,T>
         * 
         * @param <T> LinkedHashMap 中的值得类型
         * @param tclass 值类型 :null 表示Object.class
         * @return  LinkedHashMap<String,T>
         */
        @SuppressWarnings("unchecked")
        default <T> LinkedHashMap<String,T> toLhm(final Class<T> tclass){
            if(this instanceof LinkedHashMap ) return (LinkedHashMap<String,T>) this;
            final LinkedHashMap<String,T> mm = new LinkedHashMap<>();
            this.foreach(mm::put);
            return mm;
        }
        
        /**
         * 返回一个 LinkedHashMap<String,T>
         * 
         * @return LinkedHashMap<String,T>
         */
        default LinkedHashMap<String,Object> toLhm(){
            return toLhm(null);
        }
        
        /**
         * 分别对keys 和 values 进行变换。 toMap2 函数的别名。
         * 
         * @param <T> key 的类型
         * @param <U> value 的类型
         * @param keymapper key 键名变换函数:把原来的字符类型的key,转换成T类型的键名。
         * @param valuemapper value 的变换函数:把原来的Object类型的Value,转换成U类型的值。
         * @return {(t, u)} 的Map
         */
        default  <T,U> Map<T,U> applyForKvs(final Function<String, T> keymapper, Function<Object, U> valuemapper) {
           return this.toMap2(keymapper, valuemapper);
        }

        /**
         * 对键名集合进行Map,不对value 进行变换
         * @param <T> key 的类型
         * @param keymapper 键名变换函数:把原来的字符类型的key,转换成T类型的键名。
         * @return 键名变换后键值对儿({T ,Object)}
         */
        default <T> Map<T,Object> applyOnkeys(final Function<String, T> keymapper) {
            return toMap2(keymapper,identity);
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换
         * @param <T> key 的类型
         * @param keymapper 键名变换函数:把原来的字符类型的key,转换成T类型的键名。
         * @return 键名变换后键值对儿({T ,Object)}
         */
        default <T> Map<T,Object> applyOnkeys2(final Function<Integer, T> keymapper) {
            return toMap2(key->keymapper.apply(this.key2idx(key)),identity);
        }

        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param <T> key 的类型
         * @param keymapper 键名变换函数:把原来的字符类型的key,转换成T类型的键名。
         * @return 键名变换后键值对儿({T ,Object)}
         */
        default <T> Map<T,Object> aoks(final Function<String, T> keymapper) {
            return this.applyOnkeys(keymapper);
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param <T> key 的类型
         * @param keymapper 键名变换函数:把原来的字符类型的key,转换成T类型的键名。
         * @return 键名变换后键值对儿({T ,Object)}
         */
        default <T> IRecord aoks2rec(final Function<String, T> keymapper) {
            return REC(this.applyOnkeys(keymapper));
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param <T> key 键名类型
         * @param keymapper 键名变换函数:把原来的字符类型的key,转换成T类型的键名。
         * @return IRecord
         */
        default <T> Map<T,Object> aoks2(final Function<Integer, T> keymapper) {
            return this.applyOnkeys(k->keymapper.apply(this.key2idx(k)));
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param <T> key 键名类型
         * @param keymapper 键名变换函数:把原来的字符类型的key,转换成T类型的键名。
         * @return IRecord
         */
        default <T> IRecord aoks2rec2(final Function<Integer, T> keymapper) {
            return REC(this.applyOnkeys(k->keymapper.apply(this.key2idx(k))));
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param <T> key 键名类型
         * @param kk 用kk替换键名 列表,当  kk 的长度 小于 当前 IRecord的键名列表的长度是时候 不予 进行替换 返回一个自身的克隆
         * @return IRecord
         */
        default <T> IRecord aoks2rec2(String kk[]) {
            if(kk==null||kk.length<this.keys().size())return this.duplicate();
            return REC(this.applyOnkeys(k->kk[this.key2idx(k)%kk.length]));
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param <T> key 键名类型
         * @param keys 用kk替换键名 列表,用 “,” “/” “\” “空白” 给予元素分隔
         * @return IRecord
         */
        default <T> IRecord aoks2rec2(String keys) {
            final var kk = keys.split("[,/\\\\\\s]+");
            return aoks2rec2(kk);
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param <T> key 的类型
         * @param kk 用kk替换键名
         * @return 键名变换后键值对儿({T ,Object)}
         */
        @SuppressWarnings("unchecked")
        default<T> Map<T,Object> aoks2(T kk[]) {
            if(kk==null) return (Map<T,Object> )this.toMap();
            return this.aoks2(i-> i<kk.length?kk[i]:null);//aoks2
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param <T> key 的类型
         * @param keymapper 键名变换函数:把原来的字符类型的key,转换成T类型的键名。
         * @return 键名变换后键值对儿({T ,Object)}
         */
        default <T> IRecord keys(final Function<String, T> keymapper) {
            return REC(this.applyOnkeys(keymapper));
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param kk 用kk替换键名数组,对于 i>=kk.length的时候,键名的时候 的返回键名 为null, 当kk 为null 的时候返回本身。
         * @return 变换键名后的IRecord
         */
        default IRecord keys(String kk[]) {
           return REC(this.aoks2(kk));
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param kk 用kk替换键名数组,对于 i>=kk.length的时候,键名的时候 的返回键名 为null, 当kk 为null 的时候返回本身。
         * @return 变换键名后的IRecord
         */
        default IRecord keys(List<String> kk) {
           return REC(this.aoks2(kk.toArray(String[]::new)));
        }
        
        /**
         * 对键名集合进行Map,不对value 进行变换:applyOnkeys 的简写
         * @param keys 用keys替换键名数组,采用"[\\|/,\\\\]+"对键名进行分隔获得键名数组kk,对于 i>=kk.length的时候,键名的时候 的返回键名 为null, 当kk 为null 的时候返回本身。
         * @return 变换键名后的IRecord
         */
        default IRecord keys(String keys) {
           if(keys==null) return this;
           return REC(this.aoks2(keys.trim().split("[\\|/,\\\\]+")));
        }
        
        /**
         * 对值集合进行Map,不对key 进行变换<br>
         * 把函数mapper 应用到  values 对象:Object->U 对象。然后使用目标结果呈递器finisher给呈递给最终结果。<br>
         * 先转换成一个 String -> U 的Map lhm 然后把这个lhm 给转换成目标对象 O <br>
         * @param <T> Value 的值类型
         * @param <U> valuemapper 对值的变换结果：中间结果
         * @param <O> 目标结果呈递器的呈递的最终结果
         * @param valuemapper 值变换函数
         * @param finisher 目标结果呈递器O
         * @return {(String,U)} 结构的Map
         */
        @SuppressWarnings("unchecked")
        default <T,U,O> O applyOnValues(final Function<T, U> valuemapper,
                                        final Function<LinkedHashMap<String, U>, O> finisher) {
           return finisher.apply(toMap(t->valuemapper.apply((T)t)));
        }
        
        /**
         * 对值集合进行Map,不对key 进行变换
         * 把函数mapper 应用到  values 对象:Object->U 对象。
         * 转换成一个 String -> U 的Map
         * @param <T> Value 的值类型
         * @param <U> valuemapper 对值的变换结果
         * @param valuemapper 值变换函数
         * @return {(String,U)} 结构的Map
         */
        default <T,U> LinkedHashMap<String,U> applyOnValues(final Function<T, U> valuemapper) {
           return applyOnValues(valuemapper,e->e);
        }
        
        /**
         * applyOnValues:的简写
         * 对值集合进行Map,不对key 进行变换
         * 把函数mapper 应用到  values 对象:Object->U 对象。
         * 转换成一个 String -> U 的Map
         * @param <T> Value 的值类型
         * @param <U> valuemapper 对值的变换结果
         * @param valuemapper 值变换函数
         * @param finisher 目标结果呈递器O
         * @return {(String,U)} 结构的Map
         */
        default <T,U> LinkedHashMap<String,U> aovs(final Function<T, U> valuemapper,
                                                   final LinkedHashMap<String, U> finisher) {
           return applyOnValues(valuemapper,e->e);
        }
        
        /**
         * applyOnValues:的简写 <br>
         * 对值集合进行Map,不对key 进行变换<br>
         * 把函数mapper 应用到  values 对象:Object->U 对象。<br>
         * 转换成一个 String -> U 的Map<br>
         * @param <T> Value 的值类型
         * @param <U> valuemapper 对值的变换结果
         * @param valuemapper 值变换函数
         * @return {(String,U)} 结构的Map
         */
        default <T,U> LinkedHashMap<String,U> aovs(final Function<T, U> valuemapper) {
           return applyOnValues(valuemapper,e->e);
        }
        
        /**
         * applyOnValue to Record:的简写
         * 对值集合进行Map,不对key 进行变换<br>
         * 把函数mapper 应用到  values 对象:Object->U 对象。然后使用目标结果呈递器finisher给呈递给最终结果。<br>
         * 先转换成一个 String -> U 的Map lhm 然后把这个lhm 给转换成目标对象 O <br>
         * 转换成一个 String -> U 的Map<br>
         * 
         * @param <T> Value 的值类型
         * @param <U> valuemapper 对值的变换结果
         * @param valuemapper 值变换函数
         * @return {(String,U)} 结构的Map
         */
        default <T,U> IRecord aov2rec(final Function<T, U> valuemapper) {
           return applyOnValues(valuemapper,IRecord::REC);
        }
        
        /**
         * 把函数mapper 应用到 键值列表进行变换，返回一个新的IRecourd对象。
         * @param <T> mapper 的数据源类型
         * @param <U> mapper 的结果类型
         * @param mapper 对键值对儿进行数值变换的结果。
         * @return 与当前的键名相同的record 但是键值使用mapper进行变换了后的结果。
         */
        @SuppressWarnings("unchecked")
        default <T,U> IRecord apply(final Function<KVPair<String, T>, U> mapper) {
            final List<KVPair<String,U>> kvs = LIST(this.kvs().stream()
                .map(p->KVPair.KVP(p._1(),mapper.apply((KVPair<String,T>)p))));
            return KVS2REC(kvs);
        }

        /**
         * 转换成一个 String -> String 的Map
         * @return  String -> String 的Map
         */
        default  Map<String,String> toStrMap(){
            return this.toMap(e->e+"");
        }
        
        /**
         * 转换成一个 Properties 
         * @return  Properties
         */
        default Properties toProps(){
            final Properties props = new Properties();
            this.toStrMap().forEach(props::put);
            return props;
        }

        /**
         * 把value 视作一个IRecord或是可以转换成record的数据，并给予转换成IRecord
         * @param key 需要进行分解的字段名：一般未json结构的列
         * @return key 所对应对应的值得IRecord数据。
         */
        default IRecord map2rec(final String key){
            final Object value = this.get(key);// 提取值数据
            if(value ==null)return null;
            if(value instanceof IRecord) return (IRecord)value;
            return new LinkedRecord(this.asMap(key));}
        
        /**
         * 把value 视作一个IRecord或是可以转换成record的数据，并给予转换成IRecord
         * @param idx 键名索引从0开始
         * @return idx 所对应对应的值得IRecord数据。
         */
        default  IRecord map2rec(final int idx) {
            final String key = this.idx2key(idx);
            return key==null?null:map2rec(key);
        };

        /**
         * 把value 视作一个IRecord或是可以转换成record的数据，并给予转换成IRecord
         * @param key 需要进行分解的字段名：一般为键值是一个json结构的key。
         * @return key被展开后的 kv集合(IRecord),IRecord 的本意就是一组 键值集合，
         */
        default IRecord rec(final String key){
            return map2rec(key);
        }
        
        /**
         * 把key列转换成逻是时间值
         * @param idx 键名索引从0开始
         * @return idx 所对应对应的值得IRecord数据。
         */
        default IRecord rec(final int idx) {
            final String key = this.idx2key(idx);
            return key==null?null:rec(key);
        };

        /**
         * json 格式的字段转换
         * @param key 需要进行分解的字段名：一般未json结构的列
         * @return IRecord 的列表
         */
        @SuppressWarnings("unchecked")
        default List<IRecord> map2recs(final String key){
            final Object obj = this.get(key);
            if(obj==null)return null;
            if(obj instanceof List ) {
                final List<?> oo = (List<?>)obj;
                final var o = oo.stream().filter(Objects::nonNull).findAny();// 获取一个非空数据。用于类型检测。
                if(o.isPresent() && o.get() instanceof IRecord) {// 本身就是 List<IRecord> 类型，直接返回。
                    return (List<IRecord>)oo;
                }
            }
            return json2recs(str(key));
        }
        
        /**
         * 把key列转换成逻是recs的列表
         * @param idx  索引列表 从0开始
         * @return IRecord 的列表
         */
        default List<IRecord> map2recs(final int idx) {
            final String key = this.idx2key(idx);
            return key==null?null:map2recs(key);
        };

        /**
         * 把index列转换成逻是recs的列表 map2recs(别名);
         * @param idx 列索引 从0开始
         * @return recs List
         */
        default List<IRecord> recs(final int idx) {
            return map2recs(idx);
        }
        
        /**
         * 把key列转换成逻是recs的列表:map2recs(别名);
         * @param key 列名
         * @return recs List
         */
        default List<IRecord> recs(final String key) {
            return map2recs(key);
        }
        
        /**
         * 保留键名的真前缀扫描
         * 对键值儿进行扫描:所谓扫描是指 对于 [1,2,3,4] 这样的序列生成 如下的真后缀的集合(不包括空集合)：术语scan 来源于 haskell 语言
         * [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
         * fx 就是作用 真后缀的集合的元素如[1],[4,5]的函数(不包括空集合),把每个元素后缀转换成目标类型T的对象
         * @param <T> fx 目标结果类型
         * @param <X> fx 函数的源数据类型
         * @param fx 真后缀的变换函数: [(k,x)]->t
         * @return List<T> fx真前缀处理结果的集合
         */
        @SuppressWarnings("unchecked")
        default <X,T> List<T> scanl(Function<List<KVPair<String, X>>, T> fx) {
            return IRecord.scan(this.kvs().stream().map(p->KVPair.KVP(p._1(),(X)p._2())), fx);
        }
        
        /**
         * 对键值儿进行扫描:所谓扫描是指 对于 [1,2,3,4] 这样的序列生成 如下的真后缀的集合(不包括空集合)：术语scan 来源于 haskell 语言
         * [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
         * fx 就是作用 真后缀的集合的元素如[1],[4,5]的函数(不包括空集合),把每个元素后缀转换成目标类型T的对象
         * @param <T> fx 目标结果类型
         * @param <X> fx 函数的源数据类型
         * @param fx 真前缀的变换函数:xx->t
         * @return List<T> fx真前缀处理结果的集合
         */
        default <X,T> List<T> scanl2(Function<List<X>, T> fx) {
            return scanl2(fx,e->e);
        }

        /**
         * 对键值儿进行扫描:所谓扫描是指 对于 [1,2,3,4] 这样的序列生成
         * [[1],[1,2],[1,2,3],[1,2,3,4]] 这样的真前缀的集合。
         * 
         * @param <T> 目标结果类型
         * @param <X> fx 函数的源数据类型
         * @param <U> 目标结果：finisher 的返回类型
         * @param fx 真前缀的变换函数:xx->t
         * @param finisher 结果呈递函数:对fx作用后的真后缀集tt，进行再加工 递呈 最终结果 U: tt->u
         * @return U finisher 呈递 的目标结果
         */
        @SuppressWarnings("unchecked")
        default <X,T,U> U scanl2(Function<List<X>, T> fx, Function<List<T>, U> finisher) {
            var tt = IRecord.scan(this.kvs().stream().map(e->(X)e._2()), fx);
            return finisher.apply(tt);
        }

        /**
         * 保留键名的真后缀扫描
         * 对键值儿进行扫描:所谓扫描是指 对于 [1,2,3,4] 这样的序列生成 如下的真后缀的集合(不包括空集合)：术语scan 来源于 haskell 语言
         * [[5], [4, 5], [3, 4, 5], [2, 3, 4, 5], [1, 2, 3, 4, 5]]
         * fx 就是作用 真后缀的集合的元素如[1],[4,5]的函数(不包括空集合),把每个元素后缀转换成目标类型T的对象
         * @param <T> fx 目标结果类型
         * @param <X> fx 函数的源数据类型
         * @param fx 真后缀的变换函数:  [(k,x)]->t
         * @return List<T> fx真后缀处理结果的集合
         */
        @SuppressWarnings("unchecked")
        default <X,T> List<T> scanr(Function<List<KVPair<String, X>>, T> fx) {
            return IRecord.scan(this.kvs().stream().map(p->KVPair.KVP(p._1(),(X)p._2())), fx,true);
        }
        
        /**
         * 对键值儿进行扫描:所谓扫描是指 对于 [1,2,3,4] 这样的序列生成 如下的真后缀的集合(不包括空集合)：术语scan 来源于 haskell 语言
         * [[5], [4, 5], [3, 4, 5], [2, 3, 4, 5], [1, 2, 3, 4, 5]]
         * fx 就是作用 真后缀的集合的元素如[1],[4,5]的函数(不包括空集合),把每个元素后缀转换成目标类型T的对象
         * @param <T> fx 目标结果类型
         * @param <X> fx 函数的源数据类型
         * @param fx 真后缀的变换函数: xx->t
         * @return List<T> fx真后缀处理结果的集合
         */
        default <X,T> List<T> scanr2(Function<List<X>, T> fx) {
           return this.scanr2(fx,e->e);
        }

        /**
         * 对键值儿进行扫描:所谓扫描是指 对于 [1,2,3,4] 这样的序列生成 如下的真后缀的集合(不包括空集合)：术语scan 来源于 haskell 语言
         * [[5], [4, 5], [3, 4, 5], [2, 3, 4, 5], [1, 2, 3, 4, 5]]
         * fx 就是作用 真后缀的集合的元素如[1],[4,5]的函数(不包括空集合),把每个元素后缀转换成目标类型T的对象
         * @param <T> fx 目标结果类型
         * @param <X> fx 函数的源数据类型
         * @param <U> 目标结果：finisher 的返回类型
         * @param fx 真后缀的变换函数: xx->t
         * @param finisher 结果呈递函数:对fx作用后的真后缀集tt，进行再加工 递呈 最终结果 U: tt->u
         * @return U finisher呈递的目标结果
         */
        default <X,T,U> U scanr2(final Function<List<X>, T> fx, final Function<List<T>, U> finisher) {
            final var kvs = LIST(this.kvs());
            Collections.reverse(kvs);
            @SuppressWarnings("unchecked")
            final var tt = IRecord.scan(kvs.stream().map(e->(X)e._2()), fx,true);
            
            return finisher.apply(tt);
        }
        
        /**
         * gets 的别名 <br>
         * 使用bb 筛选键值对儿: 比如 提取水果的所有子集 <br>
         * final var rec = STRING2REC("苹果,西瓜,草莓,哈密瓜,鸭梨");// 水果列表 <br>
         * cph2(RPT(rec.size(),L(true,false))).map(e->rec.filter(e.bools())).map(e->MFT("{0}",e.values())) <br>
         *      .forEach(System.out::println); <br>
         * @param bb 下标选择器
         * @return bb 所筛选出来的对应字段
         */
        default IRecord filter(final Boolean[] bb) {
            return this.gets(bb);
        }
        
        /**
         * 这是按照indexes 所指定的键值进行数据过滤。默认过滤空值字段（该字段的值value为null)<br>
         * 
         * @param indexes 提取的字段键名索引序列,非负整数从0开始
         * @return 一个SimpleRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter(final Integer... indexes) {
            final var n = this.size();
            if (n <= 0)
                return REC();

            return this.filter(Arrays.stream(indexes)
                    .filter(Objects::nonNull).map(Math::abs).map(this::idx2key)
                    .toArray(String[]::new));
        }
        
        /**
         * 这是按照flds 所指定的键名进行字段过滤。默认过滤空值字段（该字段的值value为null)<br>
         * @param flds 提取的字段集合用逗号分割,flds为null 表示不进行过滤。 注意分隔符号 之间不能留有空格
         * @return 一个SimpleRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter(final String flds) {
            return this.filter(flds,true);
        }
        
        /**
         * 这是按照flds 所指定的键值进行数据否定过滤。默认过滤空值字段（该字段的值value为null) <br>
         * @param flds 提取的字段集合用逗号分割,flds为null 表示不进行过滤。
         * @return 一个SimpleRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter2(final String flds) {
            if(flds==null)return this.duplicate();
            return this.filter2(flds,true);
        }
        
        /**
         * 这是按照flds 所指定的键名进行字段过滤。默认过滤空值字段（该字段的值value为null)<br>
         * @param flds 提取的字段集合用逗号分割,flds为null 表示不进行过滤。<br>
         * 当 discard_null_field 为false 的时候，会保证返回返回的IRecord记录中包含一个完整的kk序列字段结构。<br>
         * @param discard_null_field 空值字段是否过滤。
         * @return 一个SimpleRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter(final String flds, final boolean discard_null_field) {
            String kk[] = flds==null?null:flds.split("[,、，]+");
            return this.filter(kk,discard_null_field);
        }
        
        /**
         * 这是按照flds 所指定的键名进行字段过滤。默认过滤空值字段（该字段的值value为null)<br>
         * @param flds 提取的字段集合用逗号分割,flds为null 表示不进行过滤。<br>
         * 当 discard_null_field 为false 的时候，会保证返回返回的IRecord记录中包含一个完整的kk序列字段结构。<br>
         * @param discard_null_field 空值字段是否过滤。
         * @return 一个SimpleRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter2(final String flds, final boolean discard_null_field) {
            if(flds==null)return this.duplicate();
            String kk[] = flds==null?null:flds.split("[,、，]+");
            return this.filter2(kk,discard_null_field);
        }
        
        /**
         * 这是按照flds 所指定的键名进行字段过滤。默认过滤空值字段（该字段的值value为null)<br>
         * @param flds 提取的字段集合用逗号分割,flds为null 表示不进行过滤。
         * 当 discard_null_field 为false 的时候，会保证返回返回的IRecord记录中包含一个完整的kk序列字段结构。
         * @param discard_null_field 空值字段是否过滤。
         * @return 一个SimpleRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter2(final String flds[], final boolean discard_null_field) {
            if(flds==null)return this.duplicate();
            final var aa = Arrays.asList(flds);
            return this.filter2(e->aa.contains(e._1())).filter(kvp-> !discard_null_field || kvp._2() != null);
        }
        
        /**
         * 这是按照flds 所指定的键名进行字段过滤。默认过滤空值字段（该字段的值value为null)<br>
         * @param flds 提取的字段集合用逗号分割,flds为null 表示不进行过滤。
         * 当 discard_null_field 为false 的时候，会保证返回返回的IRecord记录中包含一个完整的kk序列字段结构。
         * discard_null_field 空值字段是否过滤。默认为true
         * @return 一个SimpleRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter2(final String flds[]) {
            return filter2(flds,true);
        }
        
        /**
         * 这是按照kk 所指定的键名进行字段过滤。默认过滤空值字段（该字段的值value为null) <br>
         * @param kk 提取的字段的键值名称数据,kk 为null 表示不进行过滤。
         * @return 一个LinkedRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter(final String kk[]) {
            return filter(kk,true);
        }

        /**
         * 这是按照kk 所指定的键名进行字段过滤。默认过滤空值字段（该字段的值value为null)<br>
         * 当 discard_null_field 为false 的时候，会保证返回返回的IRecord记录中包含一个完整的kk序列字段结构。
         * @param kk 提取的字段的键值名称数据,kk 为null 表示不进行过滤。
         * @param discard_null_field 空值字段是否过滤。但相同的key只会保留一个,比如:filter(["id","id"]),只会返回一个{id:xxx}
         * @return 一个LinkedRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter(final String kk[], final boolean discard_null_field){
            final var rec = REC();
            final String[] ss = kk == null
               ? this.stream().map(Tuple2::_1).toArray(String[]::new)
               : kk;
            for(final String s:ss) {
                final var v = this.get(s);
                if(discard_null_field && v==null)continue;// 过滤掉空值字段。
                rec.add(s, this.get(s));
            }//for
            
            return rec;
        }
        
        /**
         * 这是按照pfilter 所指定的键值进行数据 否定过滤。
         * @param pfilter 字段过滤检测器,null 不进行过滤。
         * @return 一个LinkedRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter2(final Predicate<KVPair<String, Object>> pfilter) {
            return this.filter(t->!pfilter.test(t));
        }

        /**
         * 这是按照pfilter 所指定的键值进行数据 肯定过滤。
         * @param pfilter 字段过滤检测器,null 不进行过滤。
         * @return 一个LinkedRecord 以保证空值字段也可以保持顺序。
         */
        default IRecord filter(final Predicate<KVPair<String, Object>> pfilter){
            final var rec = REC();
            Predicate<KVPair<String,Object>> _pfilter = pfilter==null?e->true:pfilter;
            this.stream().filter(_pfilter).forEach(s->rec.add(s.key(),s.value()));
            return rec;
        }
        
        /**
         * 视IRecord 为一个Key-Value的数据流，把他们展开成一个U类型的数据流。
         * @param <T> 本IRecord的元素值类型
         * @param <U> 目标结果的元素类型
         * @param mapper 二元函数,把kvp展开成一个U类型的数据流
         * @return U类型数据流
         */
        @SuppressWarnings("unchecked")
        default <T,U> Stream<U> flatMap(BiFunction<String, T, Stream<U>> mapper) {
            return this.stream().flatMap(kvp->mapper.apply(kvp._1(),(T)kvp._2()));
        }
        
        /**
         * 视IRecord 为一个Key-Value的数据流，把他们展开成一个U类型的数据流。
         * @param <T> 本IRecord的元素值类型
         * @param <U> 目标结果的元素类型
         * @param mapper 一元函数,把kvp展开成一个U类型的数据流
         * @return U类型数据流
         */
        @SuppressWarnings("unchecked")
        default <T,U> Stream<U> flatMap(Function<T, Stream<U>> mapper) {
            return this.stream().flatMap(kvp->mapper.apply((T)kvp._2()));
        }
        
        /**
         * mutate 强调 高级结构变换, toTarget 强调底层数值变换，即muate是结构,toTarget是数据,对于简单类型二者有重合，可以互换 <br>
         * 
         * 汽车人变形，看我七十二变！<br>
         * 把 当前IRecord 视为一个 targetClass 对象的 的属性的 候选值 集合.类似于 把 IRecord 作为一个 Spring 的Context <br>
         * 用过 按名（按照IRecord的键)  去注入到targetClass 的对象实例 之中。 <br>
         * 看我72变化：Record的变化比72般变化还要多，哈哈 <br>
         * IRecord的变身：就像孙悟空一样变成 林林种种的 其他物件。<br>
         * 孙悟空.mutate(白骨精）：就是孙悟空变成一个白骨精。 <br>
         * targetClass 需要擁有一個 默認的 構造函數<br>
         * @param <T> mutator 所要变成的目标对象的类型
         * @param mutator 变换函数:变身逻辑
         * @return mutator 变换后的目标对象。
         */
        default <T> T mutate(final Function<IRecord, T> mutator) {
            return mutator.apply(this);
        }
        
        /**
         * mutate 强调 高级结构变换, toTarget 强调底层数值变换，即muate是结构,toTarget是数据,对于简单类型二者有重合，可以互换 <br>
         * 
         * 汽车人变形，看我七十二变！<br>
         * 把 当前IRecord 视为一个 targetClass 对象的 的属性的 候选值 集合.类似于 把 IRecord 作为一个 Spring 的Context <br>
         * 用过 按名（按照IRecord的键)  去注入(@Resource)到targetClass 的对象实例 之中。 <br>
         * 字段变身:不带有类型变换功能，对于属性字段只是强制类型转换，转换不成功则设置为null <br>
         * targetClass 需要擁有一個 默認的 構造函數( 对于 Primitive mutate 则依靠 toTarget来完成,<br>
         * mutate强调采用targetClass构造默认函数生成空实例object然后用IRecord(this)去实例化object的各个属性) <br>
         * 
         * @param <T> 目标结果类型
         * @param targetClass 目标类对象的类<br>
         * <br>
         * param enable 是否开启对 字段属性的 的默认构造, 即 对于没有出现在在当前record键名列表中的targetClass字段是否给予设置。<br>
         *  true: 表示 对于 没有在 当前keys列表中出现的 属性的 调用 其字段类型的 默认构造函数 给予  初始化。 <br>
         *  false: 表示给予丢弃。 <br>
         *  mutate的enable默认为false即不予设置默认属性对象
         * @return 目标对象T类型
         */
        default <T> T mutate(final Class<T> targetClass) {
            return this.mutate(targetClass,false);
        }

        /**
         * mutate 强调 高级结构变换, toTarget 强调底层数值变换，即muate是结构,toTarget是数据,对于简单类型二者有重合，可以互换 <br>
         * 
         * 汽车人变形，看我七十二变！<br>
         * 把 当前IRecord 视为一个 targetClass 对象的 的属性的 候选值 集合.类似于 把 IRecord 作为一个 Spring 的Context <br>
         * 用过 按名（按照IRecord的键)  去注入(@Resouce)到targetClass 的对象实例 之中。 <br>
         * 字段变身:不带有类型变换功能，对于属性字段只是强制类型转换，转换不成功则设置为null <br>
         * targetClass 需要擁有一個 默認的 構造函數( 对于 Primitive mutate 则依靠 toTarget来完成,<br>
         * mutate强调采用targetClass构造默认函数生成空实例object然后用IRecord(this)去实例化object的各个属性) <br>
         * 
         * @param <T> 目标结果类型
         * @param targetClass 目标类对象的类
         * @param enable 说是否开启对 字段属性的 的默认构造, 即 对于没有出现在在当前record键名列表中的targetClass字段是否给予设置。<br>
         *  true: 表示 对于 没有在 当前keys列表中出现的 属性的 调用 其字段类型的 默认构造函数 给予 初始化。 <br>
         *  false: 表示给予丢弃。 <br>
         * @return 目标对象T类型
         */
        @SuppressWarnings("unchecked")
        default <T> T mutate(final Class<T> targetClass, final boolean enable) {
            T bean = null; // 返回值
            
            if( targetClass==null ) return bean;// 目标targetClass对象
            
            if( targetClass.isAssignableFrom(this.getClass())  )return (T)this;// 如果 是cls的子类，则直接强制转换并返回。
            
            if( targetClass.isPrimitive() // 基础类型委托给 toTarget 
                ||targetClass.isAssignableFrom(Number.class)
                ||targetClass.isAssignableFrom(Short.class)
                ||targetClass.isAssignableFrom(Integer.class)
                ||targetClass.isAssignableFrom(Long.class)
                ||targetClass.isAssignableFrom(Float.class)
                ||targetClass.isAssignableFrom(Double.class)
                ||targetClass.isAssignableFrom(Character.class)
                ||targetClass.isAssignableFrom(Boolean.class)
                ||targetClass.isAssignableFrom(Void.class) // 这个类型我没有做特殊处理,只是写在这里而已
                ||targetClass.isAssignableFrom(Byte.class)
            ) return this.toTarget(targetClass);
            
            try{
                final var ctor = targetClass.getDeclaredConstructor();// 获取构造函数
                ctor.setAccessible(true);// 设置为可访问
                final T target = ctor.newInstance(); // 创建载体对象（承载Record的各个属性的值)
                
                // 遍历targetClass的各个字段
                Stream.of(targetClass.getDeclaredFields())
                // 对字段进行分组选取每个分组的第一个字段作为属性名(对于SimpleRecord 是可以存在同名的field的),这也是分组的原因。
                .collect(Collectors.groupingBy(Field::getName,//键为字段名称：
                    Collector.of(HashSet<Field>::new,HashSet::add,(l,r)->{l.addAll(r);return l;},
                    f->f.iterator().next())) // 敛集字段信息
                ).forEach( (name,fld)->{ // 字段遍历
                    if(!enable&&!this.has(name))return;// 如果没有开启默认设置则 对于 没有 候选值 的属性 给予放弃设置。
                    fld.setAccessible(true);/*使得字段变得可编辑*/
                    final var targetType = fld.getType(); // 获取字段类型
                    final var fldval = this.get(name); // 获取字段值
                    final Object value = (fldval!=null && (fldval instanceof IRecord))
                        ? ((IRecord)fldval).mutate(targetType,enable) // rec 类型的数据给予递归处理
                        : this.getT(name, targetType);// 提取指定類型的字段
                    if (value != null) {
                        try {
                            fld.set(target,value); // 設置字段值
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        } /* 根据键值名设置字段值,从record拷贝到Class */
                    }// value != null
                });/*foreach*/ 
                
                // 实现结果组装
                bean = target;// 成功完成对象转换
            }catch(Exception e) {
                e.printStackTrace();
            };
            
            return bean;
            
        }//mutate
        
        /**
         * 字段变身  带有简单的类型转换比如时间转换。字符串类型转换成时间对象 <br>
         * 既然mutate2比mutate 更为智能为何保留mutate呢，原因在指定targetClass的具体类型的时候，mutate比较快。 <br>
         * 另外對字段類型當目標類型與字段類型不匹配的時候mutate會採用getT來進行字段類型轉換。<br>
         * targetClass 需要擁有一個 默認的 構造函數 <br>
         * @param <T> 目标类类型。
         * @param targetClass 目标类对象的类
         * @return T类型的对象
         */
        default <T> T mutate2(final Class<T> targetClass) {
            return OBJINIT(targetClass,this);
        }
        
        /**
         * 字段浅遍历
         * @param <V> 值类型
         * @param cs 回调函数：Consumer:(k,v)->{}
         */
        @SuppressWarnings("unchecked")
        default <V> void foreach(final BiConsumer<String, V> cs) {
            this.stream().forEach(kv->cs.accept(kv.key(), (V)kv.value()));
        }
        
        /**
         * 遍历IRecord 深度遍历: Deep First Search
         * @param cs 路径结构回调函数 (路径path,path所对应的数据流)->{}, path 以 "/"开头
         */
        default void dfs(final BiConsumer<String, Stream<Object>> cs) {
            dfs(this,cs,null,null);
        }
        
        /**
         * 遍历IRecord 深度遍历: Deep First Search
         * @param <T> 元素类型
         * @param cs 路径结构回调函数 (路径path,path所对应的值列表)->{}, path 以 "/"开头
         */
        @SuppressWarnings("unchecked")
        default<T> void dfs_forall(final BiConsumer<String, List<T>> cs) {
            dfs(this,(path,stream)->cs.accept(path,
                (List<T>)(stream.collect(Collectors.toList()))),null,null);
        }
        
        /**
         * 遍历IRecord 深度遍历: Deep First Search
         * @param <T> 元素类型
         * @param cs 路径结构回调函数 (路径path,path所对应的值列表)->{}, path 以 "/"开头
         */
        @SuppressWarnings("unchecked")
        default <T> void dfs_forall2(final Consumer<Tuple2<String, List<T>>> cs) {
            this.dfs_forall((p,v)->cs.accept(TUP2(p,(List<T>)v)));
        }
        
        /**
         * 遍历IRecord 深度遍历(Deep First Search),并把遍历的结果 采用 归集器 clc 进行归集 到一个中间结果IRecord <br>
         * 最后把IRecord 给映射成U类型的结果
         * 
         * @param <T> clc的元素类型
         * @param <O> clc 的归集结果类型
         * @param <U> 结果类型
         * @param clc 每个 path 对应的 T类型数据序列的归集器 
         * @param mapper IRecord的最终结果映射器。 类型为 {path:String,value:O} ->U
         * @return U类型的结果
         */
        @SuppressWarnings("unchecked")
        default<T,O,U> U dfs_clc(final Collector<T, ?, O> clc, final Function<IRecord, U> mapper) {
            final var rec = REC();
            final BiConsumer<String,O> callback = rec::add;// dfs_forall 的回调函数
            dfs(this,(path,stream)->callback.accept(path,((Stream<T>)stream).collect(clc)),null,null);
            return mapper.apply(rec);
        }
        
        /**
         * 遍历IRecord 深度遍历(Deep First Search),并把遍历的结果 采用 归集器 clc 进行归集 到一个中间结果IRecord <br>
         * @param <T> clc的元素类型
         * @param <O> clc 的归集结果类型
         * @param clc 每个 path 对应的 T类型数据序列的归集器
         * 
         * @return IRecourd {path:String,value:O}
         */
        default<T,O> IRecord dfs_clc(final Collector<T, ?, O> clc) {
            return dfs_clc(clc,e->e);
        }
        
        /**
         * 遍历IRecord 深度遍历: Deep First Search
         * @param <T> 元素类型
         * @param cs 路径结构回调函数 (路径path,path所对应的数据的单值若为多值则取第一个元素)->{} , path 以 "/"开头
         */
        @SuppressWarnings("unchecked")
        default <T> void dfs_forone(final BiConsumer<String, T> cs) {
            dfs(this,(path,stream)->{
                //之所以采用 Optional.ofNullable 为为了保证 stream 可以容纳 null 值 
                final var opt = stream.map(Optional::ofNullable).findFirst().orElse(Optional.empty());
                cs.accept(path,(T)(opt.isPresent()?opt.get():null));
            },null,null);
        }
        
        /**
         * 遍历IRecord 深度遍历: Deep First Search
         * @param <T> 元素类型
         * @param cs 路径结构回调函数 (路径path,path所对应的数据的单值若为多值则取第一个元素)->{} , path 以 "/"开头
         */
        @SuppressWarnings("unchecked")
        default <T> void dfs_forone2(final Consumer<Tuple2<String, T>> cs) {
            this.dfs_forone((p,v)->cs.accept(TUP2(p,(T)v)));
        }
        
        /**
         * 单值式深度优先遍历计算
         * 遍历IRecord 深度遍历: Deep First Search
         * @param evaluator 指标计算器
         * @param <U> 结果的参数类型
         * @param <T> 元素的参数类型
         * @param evaluator 路径结构计算函数 (路径path,path所对应的数据的单值若为多值则取第一个元素)->U , path 以 "/"开头
         * 
         * @return U 的列表
         */
        @SuppressWarnings("unchecked")
        default <T,U> List<U> dfs_eval_forone(final BiFunction<String, T, U> evaluator) {
            final var uu = new LinkedList<U>();
            dfs(this,(path,stream)->{
                var opt = stream.findFirst();
                var u = evaluator.apply(path,(T)(opt.isPresent()?opt.get():null));
                uu.add(u);
            },null,null);
            return uu;
        }
        

        /**
         * 单值式深度优先遍历计算
         * 遍历IRecord 深度遍历: Deep First Search
         * @param evaluator 指标计算器
         * @param <U> 结果的参数类型
         * @param <T> 元素的参数类型
         * @param evaluator 路径结构计算函数 (路径path,path所对应的数据的单值若为多值则取第一个元素)->U , path 以 "/"开头
         * 
         * @return U 的流
         */
        default <T,U> Stream<U> dfs_eval_forone2(final BiFunction<String, T, U> evaluator) {
            return this.dfs_eval_forone(evaluator).stream();
        }
        
        /**
         * 多值式深度优先遍历计算
         * 遍历IRecord 深度遍历: Deep First Search
         * @param evaluator 指标计算器
         * @param <U> 结果的参数类型
         * @param <T> 元素的参数类型
         * @param evaluator 路径结构计算函数 (路径path,path所对应的数据流)->U , path 以 "/"开头
         * 
         * @return U的列表
         */
        @SuppressWarnings("unchecked")
        default <T,U> List<U> dfs_eval_forall(final BiFunction<String, Stream<T>, U> evaluator) {
            final var uu = new LinkedList<U>();
            dfs(this,(path,stream)->{
                final var u = evaluator.apply(path,(Stream<T>)stream);
                uu.add(u);
            },null,null);
            return uu;
        }
        
        /**
         * 多值式深度优先遍历计算
         * 遍历IRecord 深度遍历: Deep First Search
         * @param evaluator 指标计算器
         * @param <U> 结果的参数类型
         * @param <T> 元素的参数类型
         * @param evaluator 路径结构计算函数 (路径path,path所对应的数据流)->U , path 以 "/"开头
         * @return U 的流程
         */
        default <T,U> Stream<U> dfs_eval_forall2(final BiFunction<String, Stream<T>, U> evaluator) {
            return this.dfs_eval_forall(evaluator).stream();
        }
        
        /**
         * 结果生成：一个Key-Value的列表。
         * 遍历IRecord 深度遍历: Deep First Search
         * @param <U > 值类型:Record的值的类型，但是这个类型被隐藏了
         * @param mapper 值函数 key,key 所对应的值的集合的第一个元素。
         * 
         * @return IRecord
         */
        default <U> IRecord dfs2rec(final BiFunction<String, Stream<Object>, U> mapper) {
            final var rec = REC();
            dfs(this,(path,stream)->rec.add(path,mapper.apply(path,stream)),null,null);
            return rec;
        }
        
        /**
         * 结果生成：一个Key-Value的列表。
         * 遍历IRecord 深度遍历: Deep First Search
         * @param <U> 值类型
         * @param mapper 值函数 key,提取 key 所对应的值的集合的第一个元素 进行变换后的结果
         * @eturn mapper 值函数 key,提取 key 所对应的值的集合的第一个元素 进行变换后的结果
         */
        default <U> Map<String,U> dfs2kvs(final BiFunction<String, Stream<Object>, U> mapper) {
            final var kvs = new LinkedHashMap<String, U>();
            dfs(this,(path,stream)->kvs.put(path,mapper.apply(path,stream)),null,null);
            return kvs;
        }
        
        /**
         * 遍历IRecord 深度遍历: Deep First Search
         * @param cs 路径结构计算函数 (路径path,path所对应的数据的单值若为多值则取第一个元素)->U , path 以 "/"开头
         */
        default void dfs2(final BiConsumer<String, Object> cs) {
            dfs(this,(k,v)->cs.accept(k,v.findFirst().get()),null,null);
        }
        
        /**
         * 类似于数据的库的表连接,通过 key 把 自己与另外一个 rec 进行连接 <br>
         * a = REC("1","A","2","B","4","D"); <br>
         * b = a.join(REC("1","a","2","b","3","c")) <br>
         * 则b 就是： 1:A --> a    2:B --> b   4:D --> null    3:null --> c
         * 
         * @param rec 另外的一个连接对象
         * @return {key->TUP2<Object,Object>}的 Map
         */
        default IRecord join(final IRecord rec) {
            return REC(join(this,rec));
        }
        
        /**
         * 连接成列表 <br>
         * 类似于数据的库的表连接,通过 key 把 自己与另外一个 rec 进行连接 <br>
         * a = REC("1","A","2","B","4","D"); <br>
         * b = a.join(REC("1","a","2","b","3","c")) <br> 
         * 则b 就是： 1:A --> a    2:B --> b   4:D --> null    3:null --> c <br>
         * 
         * var x = porec.join2ll(sorec,"path,po,so".split(",")); <br>
         * 类似于这样的集合：<br>
         * path po  so <br>
         * /煤焦油/计提损耗   37180.8 (null) <br>
         * /煤焦油/徐州市龙山制焦有限公司    1.60138826E7    (null) <br>
         * 
         * @param rec 另外的一个连接对象 
         * @param keys 新生记录的键值名称 
         * @return {key->TUP2<Object,Object>}的 Map
         */
        default List<IRecord> join2rr(IRecord rec, String[] keys) {
            final var rr = new LinkedList<IRecord>();
            join(this,rec).forEach((k,tup)-> rr.add(REC(keys[0],k,keys[1],tup._1,keys[2],tup._2)));
            return rr;
        }
        
        /**
         * 连接成列表 <br>
         * 类似于数据的库的表连接,通过 key 把 自己与另外一个 rec 进行连接 <br>
         * a = REC("1","A","2","B","4","D"); <br>
         * b = a.join(REC("1","a","2","b","3","c")) <br>
         * 则b 就是： 1:A --> a    2:B --> b   4:D --> null    3:null --> c <br>
         * 
         * var x = porec.join2ll(sorec,"path,po,so".split(",")); <br>
         * 类似于这样的集合： <br>
         * path po  so <br>
         * /煤焦油/计提损耗   37180.8 (null) <br>
         * /煤焦油/徐州市龙山制焦有限公司    1.60138826E7    (null) <br>
         * 
         * @param rec 另外的一个连接对象 
         * @param keys 新生记录的键值名称 ,用逗号分割
         * @return {key->TUP2<Object,Object>}的 Map
         */
        default List<IRecord> join2rr(final IRecord rec, final String keys) {
            return join2rr(rec,(keys==null?"key,v1,v2":keys).split("[,]+"));
        }
        
        /**
         * 连接成列表 <br>
         * 类似于数据的库的表连接,通过 key 把 自己与另外一个 rec 进行连接 <br>
         * a = REC("1","A","2","B","4","D"); <br>
         * b = a.join(REC("1","a","2","b","3","c")) <br>
         * 则b 就是： 1:A --> a    2:B --> b   4:D --> null    3:null --> c <br>
         * 
         * var x = porec.join2ll(sorec,"path,po,so".split(",")); <br>
         * 类似于这样的集合：<br>
         * path po  so
         * /煤焦油/计提损耗   37180.8 (null) <br>
         * /煤焦油/徐州市龙山制焦有限公司    1.60138826E7    (null) <br>
         * 
         * @param rec 另外的一个连接对象
         * keys 新生记录的键值名称:默认为[key,v1,v2] 
         * @return {key->TUP2<Object,Object>}的 Map
         */
        default List<IRecord> join2rr(final IRecord rec) {
            return join2rr(rec,(String)null);
        }
        
        /**
         * 对于IRecord 进行排序
         * 
         * @param comparator 排序比较器
         * @return 新的IRecord 排序后
         */
        default IRecord sorted(final Comparator<? super KVPair<String, Object>> comparator){
            final var rec = REC();
            this.stream().sorted(comparator).forEach(kv -> rec.add(kv._1(), kv._2()));
            return rec;
        }
        
        /**
         * 对于IRecord 的字段进行倒排
         * @return 新的IRecord 倒排后
         */
        default IRecord reverse(){
            return this.foldRight(REC(),(kv,rec)->rec.add(kv._1(),kv._2()));
        }
        
        /**
         * 部分转换<br>
         * 把Record（一般为单元素记录：即只有一个键的Record） 转换成 目标类型对象,采用 rec2obj 转换对象,<br>
         * toTarget 一般用于提取元素的第一个键值元素。只有当第一个元素不满足要求，才尝试采用cast的方式进行整体转换。
         * 
         * @param <T> 目标类型
         * @param defaultValue 默认值,转换失败或是结果为null的时候返回默认值
         * @return T 结构的对象
         */
        @SuppressWarnings("unchecked")
        default <T> T toTarget(final T defaultValue) {
            return this.toTarget(defaultValue != null ? (Class<T>) defaultValue.getClass() : null, defaultValue);
        }
        
        /**
         * 部分转换<br>
         * 把Record（一般为单元素记录：即只有一个键的Record） 转换成 目标类型对象,采用 rec2obj 转换对象,<br>
         * toTarget 一般用于提取元素的第一个键值元素。只有当第一个元素不满足要求，才尝试采用cast的方式进行整体转换。
         * 
         * @param <T>         目标类型
         * @param targetClass 目标类型类：null 则返回IRecord本身
         * @return T 结构的对象
         */
        default <T> T toTarget(final Class<T> targetClass) {
            return this.toTarget(targetClass,null);
        }
        
        /**
         * 部分转换<br>
         * 把Record（一般为单元素记录：即只有一个键的Record） 转换成 目标类型对象,采用 rec2obj 转换对象,<br>
         * toTarget 一般用于提取元素的第一个键值元素。只有当第一个元素不满足要求，才尝试采用cast的方式进行整体转换。
         * 
         * @param <T>         目标类型
         * @param targetClass 目标类型类：null 则返回IRecord本身
         * @param defaultValue 默认值,转换失败或是结果为null的时候返回默认值
         * @return T 结构的对象
         */
        default <T> T toTarget(final Class<T> targetClass, final T defaultValue) {
            if (targetClass == null) return ((T) defaultValue);
            final var t = IRecord.rec2obj(this, targetClass);
            return t == null ? defaultValue : t;
        }
        
        /**
         * 二维矩阵<br>
         * 这个方法一般用于生成一个 列向量矩阵：比如REC("variable",new String[]{"a","b","c"}).toArray2();
         * 生成二维数组：视每个元素为单独二维数组的单独的列。
         * @return String[][] String类型的二维数组
         */
        default String[][] strmx(){
            return this.toArray2(String.class);
        }
        
        /**
         * 二维矩阵<br>
         * 这个方法一般用于生成一个 列向量矩阵：比如REC("variable",new Integer[]{1,2,3}).toArray2();
         * 生成二维数组：视每个元素为单独二维数组的单独的列。
         * @return Integer[][] Integer类型的二维数组
         */
        default Integer[][] intmx(){
            return this.toArray2(Integer.class);
        }
        
        /**
         * 二维矩阵<br>
         * 这个方法一般用于生成一个 列向量矩阵：比如REC("variable",new Double[]{1d,2d,3d}).toArray2();
         * 生成二维数组：视每个元素为单独二维数组的单独的列。
         * @return Double[][] Double类型的二维数组
         */
        default Double[][] dblmx(){
            return this.toArray2(Double.class);
        }
        
        /////////////////////////////////////////////////////////////////////
        // 以下是IRecord DataFrame 类型的方法区域:所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)
        /////////////////////////////////////////////////////////////////////
        
        /**
         * 生成一个二维数组矩阵：数组元素采用 Object 类型.
         * @return Object[][] U类型的二维数组
         */
        default Object[][] toArray2(){
            return toArray2(e->e,Object.class);
        }

        /**
         * 这个方法一般用于生成一个 列向量矩阵：比如REC("variable",new Double[]{1d,2d,3d}).toArray2();
         * 生成二维数组：视每个元素为单独二维数组的单独的列。
         * @param <U> 目标类型的数据结果
         * @param uclass 目标类型的class
         * @return U[][] U类型的二维数组
         */
        @SuppressWarnings("unchecked")
        default <U> U[][] toArray2(final Class<U> uclass){
            final var final_uclass = uclass!=null ?uclass :(Class<U>)Object.class;
            if(uclass == Object.class) 
                return (U[][])(Object)this.toArray2();
            else 
                return this.toArray2(t->IRecord.rec2obj(REC(0,t),final_uclass));
        }
        
        /**
         * 生成一个二维数组矩阵,生成数组的类型,采用t2u对于第一列元素进行 Apply,提取第一个非空元素的类型作为U类型，对于 <br>
         * 全为null的情况采用Object.class作为默认值。<br>
         * 第一列的值不存在则返回null<br>
         * @param <T> t2u的源类型，即Record 中List的中的元素类型 一般为Object,除非明确知道IRecord中的具体的数据结构
         * @param <U> t2u的目标结果的类型
         * @param t2u 值变换函数 t->u
         * @return U[][] U类型的二维数组
         */
        @SuppressWarnings("unchecked")
        default <T,U> U[][] toArray2(Function<T, U> t2u){
           final var ll  = this.lla(0, t2u);//尝试应用到第一列t2u，提取Class<U>的类型信息。
           if(ll==null)return null;// 列值不村子直接返回
           final var cellClass = ll.stream().filter(Objects::nonNull)
                .map(e->(Class<U>)e.getClass()).findFirst().orElse((Class<U>)Object.class);
          return this.toArray2(t2u, cellClass);
        }
        
        /**
         * 生成一个二维数组矩阵,生成数组的类型,采用t2u对于第一列元素进行 Apply,提取第一个非空元素的类型作为U类型，对于 <br>
         * 全为null的情况采用Object.class作为默认值。<br>
         * @param <T> t2u的源类型，即Record 中List的中的元素类型 一般为Object,除非明确知道IRecord中的具体的数据结构
         * @param <U> t2u的目标结果的类型
         * @param t2u 值变换函数 t->u
         * @param cellClass 结果容器的数据类型,cellClass 为null 视作  Object.class
         * @return U[][] U类型的二维数组
         */
        @SuppressWarnings("unchecked")
        default <T,U> U[][] toArray2(final Function<T, U> t2u, final Class<U> cellClass){
           final var shape = this.shape();
           final var final_cellClass = cellClass==null ? (Class<U>)Object.class :cellClass;
           final var ooo = this.rows().stream().map(row->row.toArray(t2u,cellClass)).toArray(n->{
                U[][] uu = null;
                uu = (U[][])Array.newInstance(final_cellClass,shape._1(),shape._2());
                return uu;
           });//ooo
           return ooo;
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 术语来源 pandas<br>
         * 返回矩阵形状<br>
         * @return (height,width)的二维矩阵
         */
        default Tuple2<Integer,Integer> shape(){
            final var width = this.keys().size();
            final var height = this.kvstream()
                .map(rec->{
                    final var vv = rec.lla("value",e->e);
                    if(vv==null)return 0;
                    else return vv.size();
                }).collect(Collectors.summarizingInt(e->e)).getMax();
            return new Tuple2<>(Math.max(height, 0),width);
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 行化操作：数据分析类 需要与DataMatrix 相结合生成 data.frame类型的 转换函数 <br>
         * 
         * row:Map 行记录 <br>
         * S:结果类型为Stream <br>
         * 主要用途就是 完成 IRecord 向 DataMatrix的转换，但是为了保证DataMatrix 与IRecord 的独立。而设置这个函数。比如 <br>
         * var dm = new DataMatrix<> (rec.rr2rowS(),Integer.class); 就构造了一个 DataMatrix 对象。
         * 
         * @return 生成一个hashmap 的集合
         */
         @SuppressWarnings("unchecked")
         default Stream<Map<String, ?>> rowS() {
             return (Stream<Map<String, ?>>) (Object)Stream.of(this.toMap());
         }

         /**
          * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
          * 行化操作：数据分析类 需要与DataMatrix 相结合生成 data.frame类型的 转换函数 <br>
          * 
          * row:Map 行记录 <br>
          * S:结果类型为Stream <br>
          * 主要用途就是 完成 IRecord 向 DataMatrix的转换，但是为了保证DataMatrix 与IRecord 的独立。而设置这个函数。比如 <br>
          * var dm = new DataMatrix<> (rec.rowS(),Integer.class); 就构造了一个 DataMatrix 对象。<br>
          * 
          * @param <T> 值类型
          * @param clazz 值类型class
          * @return 生成一个hashmap 的集合
          */
         @SuppressWarnings("unchecked")
         default <T> Stream<Map<String,T>> rowS(final Class<T> clazz) {
             return (Stream<Map<String,T>>) (Object)Stream.of(this.toMap());
         }

         /**
          * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
          * 行化操作：数据分析类 需要与DataMatrix 相结合生成 data.frame类型的 转换函数<br>
          * 
          * row:Map 行记录 <br>
          * L:结果类型为List <br>
          * 主要用途就是 完成 IRecord 向 DataMatrix的转换，但是为了保证DataMatrix 与IRecord 的独立。而设置这个函数。比如 <b>
          * var dm = new DataMatrix<> (rec.rowS(),Integer.class); 就构造了一个 DataMatrix 对象。<br>
          * 
          * @param <T> 值类型
          * @param clazz 值类型class
          * @return 生成一个hashmap 的集合
          */
         @SuppressWarnings("unchecked")
         default <T> List<Map<String,T>> rowL(final Class<T> clazz) {
             return (List<Map<String,T>>) (Object) Collections.singletonList(this.toMap());
         }

         /**
          * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
          * 行化操作：数据分析类 需要与DataMatrix 相结合生成 data.frame类型的 转换函数<br>
          * 
          * row:Map 行记录<br>
          * L:结果类型为List<br>
          * 主要用途就是 完成 IRecord 向 DataMatrix的转换，但是为了保证DataMatrix 与IRecord 的独立。而设置这个函数。比如 <br>
          * var dm = new DataMatrix<> (rec.rowL(),Integer.class); 就构造了一个 DataMatrix 对象。<br>
          * 
          * @return 生成一个hashmap 的集合<br>
          */
         default List<Map<String,Object>> rowL() {
             return Collections.singletonList(this.toMap());
         }

        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 返回行列表:<br>
         *  final var dfm = REC( <br>
         *    "A",L("a","b","c"), // 第一列 <br>
         *    "B",L(1,2,3), // 第二列 <br>
         *    "C",A(2,4,6,10), // 第三列 <br>
         *    "D",REC(0,3,1,6,2,9), // 第四列,需要注意这是一个  (0,3),(1,6),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *    "E",REC(0,31,1,61,2,91).toMap() // 第五列，需要注意这是一个  (0,31),(1,61),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *  );// dfm <br>
         *  
         *  返回:<br>
         *  A:a    B:1    C:2    D:3    E:31 <br>
         *  A:b    B:2    C:4    D:6    E:61 <br>
         *  A:c    B:3    C:6    D:9    E:91 <br>
         *  A:a    B:1    C:10    D:3    E:31 <br>
         * @param <T> 结果类型  Target
         * @param <V> 源数据的值类型 Value
         * @param mapper 元素类型格式化函数,类型为， (key:String,value:Object)->new_value
         * @param hh 列名序列,若为空则采用EXCEL格式的列名称(0:A,1:B,...),如果列表不够也采用excelname给予填充区别只不过添加了一个前缀"_"
         * @return 返回以hh值为列名的行列表
         */
        @SuppressWarnings("unchecked")
        default <T,V> List<IRecord> rows(final BiFunction<String, V, T> mapper, final List<String> hh) {
            final var shape = this.shape();// 提取图形结构
            final var rows = new ArrayList<IRecord>(shape._1());// 提取行数记录行数
            final List<String> final_hh = hh == null
                ? LIST(Stream.iterate(0, i->i+1).limit(shape._2()).map(LittleTree::excelname))// 生成excel列名
                : hh;
            if(hh!=null)Stream.iterate(hh.size(),i->i<shape._2(),i->i+1).forEach(i-> final_hh.add(excelname(i)));
            final var keys = this.keys().toArray(String[]::new);
            for(int j=0;j<shape._2();j++) {// 列号
                final var col = this.lla(keys[j],e->e);// 提取name列
                if(col==null)continue;
                final var size = col.size();// 列大小
                for(int i=0;i<shape._1();i++) { // 列名索引
                    if(rows.size()<=i)rows.add(REC());
                    final var row = rows.get(i);// 提取i 行的数据记录。
                    final var key = final_hh.get(j);
                    row.add(key,mapper.apply(keys[j],(V)col.get(i%size)));
                }//for i
             }// keys
           return rows;
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 返回行列表:<br>
         *  final var dfm = REC( <br>
         *    "A",L("a","b","c"), // 第一列 <br>
         *    "B",L(1,2,3), // 第二列 <br>
         *    "C",A(2,4,6,10), // 第三列 <br>
         *    "D",REC(0,3,1,6,2,9), // 第四列,需要注意这是一个  (0,3),(1,6),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *    "E",REC(0,31,1,61,2,91).toMap() // 第五列，需要注意这是一个  (0,31),(1,61),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *  );// dfm <br>
         *  
         *  返回:<br>
         *  A:a B:1 C:2 D:3 E:31 <br>
         *  A:b B:2 C:4 D:6 E:61 <br>
         *  A:c B:3 C:6 D:9 E:91 <br>
         *  A:a B:1 C:10    D:3 E:31 <br>
         * 
         * @param <T> 转换mapper的 结果类型
         * @param <V> 源数据的值类型 Value
         * @param mapper 元素类型格式化函数,类型为， (key:String,value:Object)->new_value
         * hh列名序列,默认为keys
         * @return 返回以key值为列名的行列表
         */
        default <T,V> List<IRecord> rows(final BiFunction<String, V, T> mapper) {
            return rows(mapper,this.keys());
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 返回行列表:<br>
         *  final var dfm = REC( <br>
         *    "A",L("a","b","c"), // 第一列 <br>
         *    "B",L(1,2,3), // 第二列 <br>
         *    "C",A(2,4,6,10), // 第三列 <br>
         *    "D",REC(0,3,1,6,2,9), // 第四列,需要注意这是一个  (0,3),(1,6),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *    "E",REC(0,31,1,61,2,91).toMap() // 第五列，需要注意这是一个  (0,31),(1,61),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *  );// dfm <br>
         *  
         *  返回:<br>
         *  A:a B:1 C:2 D:3 E:31 <br>
         *  A:b B:2 C:4 D:6 E:61 <br>
         *  A:c B:3 C:6 D:9 E:91 <br>
         *  A:a B:1 C:10    D:3 E:31 <br>
         *  
         *  @return 返回以key值为列名的行列表
         */
        default List<IRecord> rows() {
            return this.rows((key,value)->value,this.keys());
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 返回行列表:<br>
         *  final var dfm = REC( <br>
         *    "A",L("a","b","c"), // 第一列 <br>
         *    "B",L(1,2,3), // 第二列 <br>
         *    "C",A(2,4,6,10), // 第三列 <br>
         *    "D",REC(0,3,1,6,2,9), // 第四列,需要注意这是一个  (0,3),(1,6),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *    "E",REC(0,31,1,61,2,91).toMap() // 第五列，需要注意这是一个  (0,31),(1,61),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *  );// dfm <br>
         *  
         *  返回:<br>
         *  A:a B:1 C:2 D:3 E:31 <br>
         *  A:b B:2 C:4 D:6 E:61 <br>
         *  A:c B:3 C:6 D:9 E:91 <br>
         *  A:a B:1 C:10    D:3 E:31 <br>
         *  
         *  @return 返回以key值为列名的行 的流
         */
        default Stream<IRecord> rows2() {
            return this.rows().stream();
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 返回行列表:<br>
         *  final var dfm = REC( <br>
         *    "A",L("a","b","c"), // 第一列 <br>
         *    "B",L(1,2,3), // 第二列 <br>
         *    "C",A(2,4,6,10), // 第三列 <br>
         *    "D",REC(0,3,1,6,2,9), // 第四列,需要注意这是一个  (0,3),(1,6),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *    "E",REC(0,31,1,61,2,91).toMap() // 第五列，需要注意这是一个  (0,31),(1,61),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *  );// dfm <br>
         *  
         *  返回:<br>
         *  A:a B:1 C:2 D:3 E:31 <br>
         *  A:b B:2 C:4 D:6 E:61 <br>
         *  A:c B:3 C:6 D:9 E:91 <br>
         *  A:a B:1 C:10    D:3 E:31 <br>
         *  
         *  @param predicate 检索过滤谓词
         *  @return 返回以key值为列名的行 的流
         */
        default Stream<IRecord> rows2(final Predicate<IRecord> predicate) {
            return this.rows2().filter(predicate);
        }
        
        /**
         * 第rowid 所在的行记录
         * @param rowid 行号索引：从0开始
         * @return rowid所标记行记录
         */
        default IRecord row(int rowid) {
            final var rows = this.rows((name,e)->e,this.keys());
            if(rows==null||rows.size()<1||rows.size()<=rowid)return null;
            return rows.get(rowid);
        }
        
        /**
         * 返回idx 位置的列元素集合
         * 
         * @param idx 列名索引，从0开始
         * @return idx 所标识的列(key)的元素集合
         */
        default List<Object> column(Integer idx){
            return this.lla(idx, e->e);
        }

        /**
         * 返回idx 列索引位置的列数据:列表
         *  
         * @param <T> 列的元数据类型
         * @param <U> 返回值变换后的列的类型
         * @param idx 列名索引，从0开始
         * @param t2u 列值转换函数:t->u
         * @return idx 所标识的列(key)的经过t2u变换后的元素集合
         */
        default <T,U> List<U> column(Integer idx, Function<T, U> t2u){
            return this.lla(idx, t2u);
        }

        /**
         * 返回colName的列元素集合：强制转换为targetClass 的类型 <br>
         * 
         * 类型采用强制转换，因此可能会出现不同列之间的类型不一致的风险，使用时候需要注意。这一部分需要在编程中给注意与防范。<br>
         * 类库设置不予考虑。<br>
         * 
         * @param <T> 列的元数据类型
         * @param colName 列名
         * @param targetClass 列的值类型类
         * @return idx 所标识的列(key)的元素集合(强制姐转换为T类型)
         */
        @SuppressWarnings("unchecked")
        default <T> List<T> column(String colName, Class<T> targetClass){
            return this.lla(colName, e->(T)e);
        }

        /**
         * 提取columnName 所在的列数据列表
         *  
         * @param <T> 列的元数据类型
         * @param <U> 返回值变换后的列的类型
         * @param columnName 列名：这是对lla的别名
         * @param t2u 列值转换函数 :t->u
         * @return columnName 所标识的列(key)的经过t2u变换后的元素集合
         */
        default <T,U> List<U> column(String columnName, Function<T, U> t2u){
            return this.lla(columnName, t2u);
        }

        /**
         * 
         * 返回idx 位置的列元素集合：：强制转换为targetClass 的类型
         * 
         * 类型采用强制转换，因此可能会出现不同列之间的类型不一致的风险，使用时候需要注意。这一部分需要在编程中给注意与防范。<br>
         * 类库设置不予考虑。<br>
         * 
         * @param <T> 列的元数据类型
         * @param idx 列名索引，从0开始
         * @param targetClass 列的值类型类
         */
        @SuppressWarnings("unchecked")
        default <T> List<T> column(Integer idx, Class<T> targetClass){
            return this.lla(idx, e->(T)e);
        }

        /**
         * 提取所有的列数据列表
         * 
         * @param <T> 列的元数据类型
         * @param <U> 返回值变换后的列的类型
         * @param t2u 列值转换函数:t->u
         * @return 列集合每个列族使一个U类型的列表
         */
        default <T,U> List<List<U>> columns(Function<T, U> t2u){
            return this.keys().stream().map(name->this.lla(name, t2u)).collect(Collectors.toList());
        }
        
        /**
         * 返回所有的列的数据的列表 <br>
         * 
         * 类型采用强制转换，因此可能会出现不同列之间的类型不一致的风险，使用时候需要注意。这一部分需要在编程中给注意与防范。<br>
         * 类库设置不予考虑。<br>
         * 
         * @param <T> 列的元数据类型
         * @return 列集合每个列族使一个U类型的列表
         */
        @SuppressWarnings("unchecked")
        default <T> List<List<T>> columns(Class<T> targetClass){
            return this.keys().stream().map(name->this.lla(name,e->(T)e)).collect(Collectors.toList());
        }
        
        /**
         * 提取列值集合：通通返回List &lt;Object&gt
         * @return 列集合每个列族使一个U类型的列表
         */
        default List<List<Object>> columns(){
            return this.keys().stream().map(name->this.lla(name,e->e)).collect(Collectors.toList());
        }
        
        /**
         * 提取列值集合：把列转换成U类型的对象。
         *
         * @param <T> 源数据列表的元素类型
         * @param <U> 目标列的结果类型
         * @param tt2u 列值转换函数:tt->u
         * @return 列集合每个列族使一个IRecord类型的列表
         */
        default <T,U> List<U> columnL(Function<List<T>, U> tt2u){
            return this.columns2(tt2u).collect(Collectors.toList());
        }
        
        /**
         * 提取列值集合：把列转换成IRecord
         * 
         * @return 列集合每个列族使一个IRecord类型的列表
         */
        default List<IRecord> columnL(){
            return this.columnL(IRecord::L2REC);
        }
        
        /**
         * 提取列值集合：把列转换成U类型的对象。
         *
         * @param <T> 源数据列表的元素类型
         * @param <U> 目标列的结果类型
         * @param tt2u 列值转换函数:tt->u
         * @return 列集合每个列族使一个IRecord类型的流
         */
        @SuppressWarnings("unchecked")
        default <T,U> Stream<U> columns2(final Function<List<T>, U> tt2u){
            return this.keys().stream().map(name->(tt2u.apply((List<T>)this.lla(name, t->(T)t))));
        }

        /**
         * 提取列值集合：把列转换成IRecord
         *
         * @return 列集合每个列族使一个IRecord类型的列表
         */
        default Stream<IRecord> columns2(){
            return this.columns2(IRecord::L2REC);
        }
        
        /**
         * 生成一个 数据透视表:参照Excel的实现。<br>
         * 简单说说就是把 一个 记录集合的列表 rr：<br>
         * a    b   c   d <br>
         * ..   ..  ..  ..<br>
         * ..   ..  ..  ..<br>
         * 分类成成 a/b/c [(a,b,c,d)],即如下图所示的 分组的层次结构，可以所所谓透视就是对一个列表 rr进行分组再分组的过程，亦即 递归分组。<br>
         * a0 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d0],[a0 b0 c0 d1],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d2],[a0 b0 c0 d3],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d4],[a0 b0 c0 d5],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d6],[a0 b0 c0 d7'],...] <br>
         * a1 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a1 b0 c0 d7],[a1 b0 c0 d9],...] <br>
         * - - c1 <br>
         * - - - [[a1 b0 c1 d10],[a1 b0 c1 d11],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a1 b1 c0 d12],[a1 b1 c0 d12],...] <br>
         * - - c1 <br>
         * - - - [[a1 b1 c1 d14],[a1 b1 c1 d15],...] <br>
         * <br>
         * 这样的层级结构。然后再对每个分组计算：调用函数 evaluator 结算集合的指标结果 U<br>
         * <br>
         * 例如:rr 需要包含：sale_name,goods_name 的key,以及 number 的值字段。<br>
         * var result = IRecord.pivotTable( rr, <br>
         *  "sale_name,goods_name".split(","), <br>
         *  ee->ee.stream().collect(Collectors.summarizingDouble(e->e.dbl("number"))).getSum() <br>
         * ); <br>
         * 
         * 待分类的数据集合(rr)。即源数据,采用默认的this.rows()<br>
         * 指标计算器evaluator 列指标：分类结果的计算器，采用LittleTree::LIST<br>
         * <br>
         * @param keys 分类的key列表，分类依据字段列表。或者说 分类层级的序列
         * @return 一个包含由层级关系 IRecord. 中间节点是IRecord类型，叶子节点是 U 类型。
         */
        default IRecord pivotTable(final Object... keys) {
            return this.rows().stream().collect(pvtclc(keys));
        }
        
        /**
         * 生成一个 数据透视表:参照Excel的实现。<br>
         * 简单说说就是把 一个 记录集合的列表 rr：<br>
         * a    b   c   d <br>
         * ..   ..  ..  ..<br>
         * ..   ..  ..  ..<br>
         * 分类成成 a/b/c [(a,b,c,d)],即如下图所示的 分组的层次结构，可以所所谓透视就是对一个列表 rr进行分组再分组的过程，亦即 递归分组。<br>
         * a0 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d0],[a0 b0 c0 d1],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d2],[a0 b0 c0 d3],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d4],[a0 b0 c0 d5],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d6],[a0 b0 c0 d7'],...] <br>
         * a1 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a1 b0 c0 d7],[a1 b0 c0 d9],...] <br>
         * - - c1 <br>
         * - - - [[a1 b0 c1 d10],[a1 b0 c1 d11],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a1 b1 c0 d12],[a1 b1 c0 d12],...] <br>
         * - - c1 <br>
         * - - - [[a1 b1 c1 d14],[a1 b1 c1 d15],...] <br>
         * <br>
         * 这样的层级结构。然后再对每个分组计算：调用函数 evaluator 结算集合的指标结果 U<br>
         * <br>
         * 例如:rr 需要包含：sale_name,goods_name 的key,以及 number 的值字段。<br>
         * var result = IRecord.pivotTable( rr, <br>
         *  "sale_name,goods_name".split(","), <br>
         *  ee->ee.stream().collect(Collectors.summarizingDouble(e->e.dbl("number"))).getSum() <br>
         * ); <br>
         * 
         * 待分类的数据集合(rr)。即源数据,采用默认的this.rows()<br>
         * 指标计算器evaluator 列指标：分类结果的计算器，采用LittleTree::LIST<br>
         * <br>
         * @param keys 分类 的层级key列表，分类依据字段列表。或者说 分类层级的序列，采用',','\'和'/' 进行分隔,
         * null 或者空白字符，默认为record的keys()作为分类层级。
         * @return 一个包含由层级关系 IRecord. 中间节点是IRecord类型，叶子节点是 U 类型。
         */
        default IRecord pivotTable(final String keys) {
            final var kk = keys!=null && !keys.matches("\\s*") // 输入参数的有效性检查
                ? Arrays.stream(keys.split("[,\\\\/]+")).map(String::strip).toArray() // 转换成Object[]
                : null; // 分类 的层级key列表
            return this.rows().stream().collect(pvtclc(kk));
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 返回行列表:<br>
         *  final var dfm = REC( <br>
         *    "A",L("a","b","c"), // 第一列 <br>
         *    "B",L(1,2,3), // 第二列 <br>
         *    "C",A(2,4,6,10), // 第三列 <br>
         *    "D",REC(0,3,1,6,2,9), // 第四列,需要注意这是一个  (0,3),(1,6),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *    "E",REC(0,31,1,61,2,91).toMap() // 第五列，需要注意这是一个  (0,31),(1,61),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *  );// dfm
         *  
         *  返回:<br>
         *  A    B    C    D    E <br>
         *  a    1    2    3    31 <br>
         *  b    2    4    6    61 <br>
         *  c    3    6    9    91 <br>
         *  a    1    10    3    31 <br>
         *  
         * 按照列进行展示
         * 对DataFrame进行初始化
         * @param key_formatter 键名内容初始化
         * @param cell_formatter 键值元素内容初始化
         * @Return 格式化字符串
         */
        default String toString2(
                final Function<Object, String> key_formatter,
                final Function<Object, String> cell_formatter) {
            
           final var builder = new StringBuilder();
           final var final_cell_formatter = cell_formatter!=null?cell_formatter:frt(2);
           final var final_key_formatter = key_formatter!=null?key_formatter:frt(2);
           builder.append(this.keys().stream().map(final_key_formatter).collect(Collectors.joining("\t"))).append("\n");
           this.rows().forEach(rec->{
               builder.append(rec.values().stream()
                    .map(final_cell_formatter)
                    .collect(Collectors.joining("\t")));
               builder.append("\n");
           });// forEach
           return builder.toString();
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 返回行列表:<br>
         *  final var dfm = REC( <br>
         *    "A",L("a","b","c"), // 第一列 <br>
         *    "B",L(1,2,3), // 第二列 <br>
         *    "C",A(2,4,6,10), // 第三列 <br>
         *    "D",REC(0,3,1,6,2,9), // 第四列,需要注意这是一个  (0,3),(1,6),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *    "E",REC(0,31,1,61,2,91).toMap() // 第五列，需要注意这是一个  (0,31),(1,61),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *  );// dfm
         *  
         *  返回:<br>
         *  A   B   C   D   E <br>
         *  a   1   2   3   31 <br>
         *  b   2   4   6   61 <br>
         *  c   3   6   9   91 <br>
         *  a   1   10  3   31 <br>
         *  
         * 按照列进行展示
         * 对DataFrame进行初始化
         * @param cell_formatter 元素内容初始化
         * @Return 格式化字符串
         */
        default String toString2(final Function<Object, String> cell_formatter) {
            return this.toString2(null,cell_formatter);
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 返回行列表:<br>
         *  final var dfm = REC( <br>
         *    "A",L("a","b","c"), // 第一列 <br>
         *    "B",L(1,2,3), // 第二列 <br>
         *    "C",A(2,4,6,10), // 第三列 <br>
         *    "D",REC(0,3,1,6,2,9), // 第四列,需要注意这是一个  (0,3),(1,6),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *    "E",REC(0,31,1,61,2,91).toMap() // 第五列，需要注意这是一个  (0,31),(1,61),...,这样的(key,value)序列，而不是单纯的值 序列 <br>
         *  );// dfm
         *  
         *  返回:<br>
         *  A   B   C   D   E <br>
         *  a   1   2   3   31 <br>
         *  b   2   4   6   61 <br>
         *  c   3   6   9   91 <br>
         *  a   1   10  3   31 <br>
         *  
         * 按照列进行展示
         * 对DataFrame进行初始化
         * @Return 格式化字符串
         */
        default String toString2() {
            return toString2(null);
        }
        
        /**
         * Unpivot a DataFrame from wide to long format, optionally leaving identifiers set <br>
         * 
         * - mapper 元素类型格式化函数,类型为， (key:String,value:Object)->new_value <br>
         * - hh 列名序列,若为空则采用EXCEL格式的列名称(0:A,1:B,...),如果列表不够也采用excelname给予填充区别只不过添加了一个前缀"_" <br>
         * @param id_vars Column(s) to use as identifier variables.
         * @param value_vars Column(s) to unpivot. If not specified, uses all columns that are not set as id_vars.
         * @param var_name scalarName to use for the ‘variable’ column. If null use  ‘variable’.
         * @param value_name Name to use for the ‘value’ column.
         * @return Unpivoted DataFrame.
         */
        default IRecord melt(final List<String> id_vars, final List<String> value_vars,
                             final String var_name, final String value_name){
            return _melt((s,e)->e,null,id_vars,value_vars,var_name, value_name);
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 术语来源于：R reshape, 接口 原型来源于 pandas
         * Unpivot a DataFrame from wide to long format, optionally leaving identifiers set <br>
         * 
         * - mapper 元素类型格式化函数,类型为， (key:String,value:Object)->new_value <br>
         * - hh 列名序列,若为空则采用EXCEL格式的列名称(0:A,1:B,...),如果列表不够也采用excelname给予填充区别只不过添加了一个前缀"_" <br>
         * @param id_vars Column(s) to use as identifier variables.
         * @param value_vars Column(s) to unpivot. If not specified, uses all columns that are not set as id_vars. <br>
         * - var_names scalarName to use for the ‘variable’ column. If null use  ‘variable’. <br>
         * - value_name Name to use for the ‘value’ column. <br>
         * @return Unpivoted DataFrame.
         */
        default IRecord melt(final List<String> id_vars, final List<String> value_vars){
            
            return _melt((s,e)->e,null,id_vars,value_vars,"variable","value");
        }
        
        /**
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 术语来源于：R reshape, 接口 原型来源于 pandas
         * Unpivot a DataFrame from wide to long format, optionally leaving identifiers set <br>
         * 
         * @param <T> 中间结果类型: 由 mapper: (k:String,o:Object)->t:T 生成。
         * @param mapper 元素类型格式化函数,类型为， (key:String,value:Object)->new_value:T
         * @param hh 列名序列,若为空则采用EXCEL格式的列名称(0:A,1:B,...),如果列表不够也采用excelname给予填充区别只不过添加了一个前缀"_"
         * 
         * @param id_vars 标识变量集合 Column(s) to use as identifier variables.
         * @param value_vars 值变量集合 Column(s) to unpivot. If not specified, uses all columns that are not set as id_vars.
         * @param var_name 窄长scalarName to use for the ‘variable’ column. If null use  ‘variable’.
         * @param value_name Name to use for the ‘value’ column.
         * @return Unpivoted DataFrame. 窄长型数据
         */
        default <T> List<IRecord> melt2recs(final BiFunction<String, Object, T> mapper, final List<String> hh,
                                            final List<String> id_vars, final List<String> value_vars, final String var_name, final String value_name) {
            
            final var final_id_vars = id_vars;// identifier variables names,id标识变量名称集合
            final var final_value_vars = value_vars;// variables names,即值变量名称集合 
            final var final_var_name = var_name;// 新生成的值变量字段名称:分组名称
            final var final_value_name = value_name;// 新生成的值变量字段名称
            final var idvars = final_id_vars.toArray(new String[0]);// 标识字段名称。
            
            /**
             * 对于宽结构的数据矩阵：我们一般把它视为一个列向量集合。(v1,v2,v3,...). 由于 每个向量vi 都表示数据(总体)的一种特定属性，拥有一定数据范围
             * 有时又把它称为变量variable，即数据表格中的列在数据分析与操作中被视为变量variable
             * 
             * 在具体应用中每个变量vi 的意义是不相同的,它们又可以分为两类 {idvars:id标识向量集合} 和 {value_vars:value向量集合} 来表达层级结构，因此可以
             * 根据idvars 和value_vars 来构造出层级结构。比如：
             * 一条数据记录：(id11:idvar, id12:idvar2 ,value11:value_var1, value12:value_var2,value13:value_var3) 就可以表示为
             * 以下的树形结构（层级结构)
             *    (id11:idvar1,id12:idvar2)                      张:姓氏, 三:名字 
             *         |---- value11: value_var1                        |---- 18601690610 电话 
             *         |---- vlaue12: value_var2                        |---- gbench@sina.com 邮箱 
             *         |---- value13: value_var3                        |---- 上海徐家汇法华镇路 地址
             * 分析上述结构，就会发现 这其实是一种融合操作：value_vars 集合的变量的名称给汇集成一个新的变量/列var_name, 并把相对的值汇聚成 value_name变量/列
             *  idvar1    idvar2    var_name    value_name        姓    名    属性    属性值
             *  value11 vlaue12  value_var1   value11             张    三     电话   18601690610 
             *  value11 vlaue12  value_var2   vlaue12             张    三     邮箱    gbench@sina.com
             *  value11 vlaue12  value_var3   vlaue13             张    三     地址   上海徐家汇法华镇路
             * 这是把短宽型1x5的数据 给 转换成 窄长型3x4的数据的 变换方式。
             */
            
            final var items = this.rows(mapper, hh).stream().flatMap( // DataFrame  的行记录名称
                wide_rec->{// 待进行分解的短宽型数据记录
                    // 采用原型法来构架窄记录，
                    final var proto = wide_rec.filter(idvars);// 制作原型数据, 即长窄型数据的前导部分的 idvars部分的数据：前导记录
                    final var value_vars_left = new AtomicInteger(value_vars.size());// 剩余尾槌的value_vars数量
                    return final_value_vars.stream().map(value_var->{// 依次把属性字段信息 value_vars 加入到  protod额后半段中
                        final var narrow_item = value_vars_left.getAndDecrement() != 1 // 当剩下有多个时候用副本否则直接使用原型，避免浪费
                        ?   proto.duplicate() // 窄长属性记录的前半段：标识变量部分。采用对proto的副本进行追加的方式来构造
                        :   proto;// 最后一条记录使用原型 
                        narrow_item.add(final_var_name, value_var);// 把值属性名value_var增加到final_var_name 列名下
                        narrow_item.add(final_value_name, wide_rec.get(value_var));// 把值属性value_var的值增加到final_value_name 列名下
                        return narrow_item;// 返回新生成窄记录
                    });// return 依据wide_rec新生成窄记录 narrow_item 集合：这是一对多的变换
                }).collect(Collectors.toList());// flatMap
            
            return items;// 窄长数据的集合
        }
        
        /**
         * 一般用于内部调用
         * DataFrame 类型的数据方法,所谓DataFrame 是指键值对儿中的值为List的IRecord(kvs)<br>
         * 术语来源于：R reshape, 接口 原型来源于 pandas
         * 
         * Unpivot a DataFrame from wide to long format, optionally leaving identifiers set <br>
         * 
         * @param <T> 中间结果类型: 由 mapper: (k:String,o:Object)->t:T 生成。
         * @param mapper 元素类型格式化函数,类型为， (key:String,value:Object)->new_value:T
         * @param hh 列名序列,若为空则采用EXCEL格式的列名称(0:A,1:B,...),如果列表不够也采用excelname给予填充区别只不过添加了一个前缀"_"
         * 
         * @param id_vars Column(s) to use as identifier variables.
         * @param value_vars Column(s) to unpivot. If not specified, uses all columns that are not set as id_vars.
         * @param var_name scalarName to use for the ‘variable’ column. If null use  ‘variable’.
         * @param value_name Name to use for the ‘value’ column.
         * @return Unpivoted DataFrame.
         */
        default <T> IRecord _melt(
                final BiFunction<String, Object, T> mapper,
                final List<String> hh,
                final List<String> id_vars, final List<String> value_vars,
                final String var_name, final String value_name) {
            final var dfm = REC();// 生成一个DataFrame
            this.melt2recs(mapper, hh, id_vars, value_vars, var_name, value_name)
            .forEach(item->{
                item.kvs().forEach(p-> dfm.computeIfAbsent(p.key(), _k-> new LinkedList<>())
                .add(p.value()));// item.kvs()
            });// forEach
            
            return dfm;
        }
        
        /**
         * 判断键值是否都满足表达式
         * @param <T> 元素类型
         * @param predicate 兼职的判断函数:(key,value)->boolean
         * @return 是否所有的值都匹配表达式 predicate
         */
        @SuppressWarnings("unchecked")
        default <T> boolean allMatch(BiPredicate<String, T> predicate){
            return this.kvs().stream().allMatch(e->predicate.test(e.key(),(T)e.value()));
        }
        
        /**
         * 判断键值是否都满足表达式
         * @param <T> 元素类型
         * @param predicate 兼职的判断函数
         * @return 是否所有的值都匹配表达式 predicate
         */
        @SuppressWarnings("unchecked")
        default <T> boolean allMatch(Predicate<T> predicate){
            return this.values().stream().map(e->(T)e).allMatch(predicate);
        }
        
        /**
         * 判断键值是否有满足predicate的元素
         * @param <T> 元素类型
         * @param predicate 兼职的判断函数
         * @return 判断键值是否有满足predicate的元素
         */
        @SuppressWarnings("unchecked")
        default <T> boolean anyMatch(Predicate<T> predicate){
            return this.values().stream().map(e->(T)e).anyMatch(predicate);
        }
        
        /**
         * 判断键值是否有满足predicate的元素
         * @param <T> 元素类型
         * @param predicate 兼职的判断函数:(key,value)->boolean
         * @return 判断键值是否有满足predicate的元素
         */
        @SuppressWarnings("unchecked")
        default <T> boolean anyMatch(BiPredicate<String, T> predicate){
            return this.kvs().stream().anyMatch(e->predicate.test(e.key(),(T)e.value()));
        }
        
        /**
         * 判断键值元素是否都为typeClass的T的类型
         * @param <T> 元素类型
         * @param typeClass 结果类类型
         * @return 判断键值是否有满足predicate的元素
         */
        default <T> boolean typeOf(Class<T> typeClass){
            return this.allMatch(e->typeClass.isAssignableFrom(e.getClass()));
        }
        
        /**
         * 原型法构造对象：对象衍生化，对象产生自:proto.derive(props) <br>
         * 只是duplicate 与add 混合。 <br>
         * 相当于  this.duplicate().add(_REC(props)); 的操作用户采用原型的方式进行 创建数据对象。  <br>
         * 标准版的记录生成器, map 生成的是LinkedRecord <br>
         * @param props 自定义属性的  键,值序列:key0,value0,key1,value1,....
         * @return 衍生于 proto(this)的IRecord对象
         */
        default IRecord derive(final Object... props) {
            return this.duplicate().add(_REC(props));
        }
        
        /**
         * 原型法构造对象：对象衍生化，对象产生自:proto.derive(props) <br>
         * 只是duplicate 与set 混合。 <br>
         * 相当于  this.duplicate().set(idx, value); 的操作用户采用原型的方式进行 创建数据对象。  <br>
         * 标准版的记录生成器, map 生成的是LinkedRecord <br>
         * @param idx 索引号从0开始
         * @param value 值对象
         * @return 衍生于 proto(this)的IRecord对象
         */
        default IRecord derive(final int idx, final Object value) {
            return this.duplicate().set(idx, value);
        }
        
        /**
         * 原型法构造对象：对象衍生化，对象产生自:proto.derive(props) <br>
         * 只是duplicate 与add 混合。<br>
         * 相当于  this.duplicate().add(rec); 的操作用户采用原型的方式进行 创建数据对象。  <br>
         * 标准版的记录生成器, map 生成的是LinkedRecord <br>
         * @param rec IRecord对象
         * @return 衍生于 proto(this)的IRecord对象
         */
        default IRecord derive(IRecord rec) {
            return this.duplicate().add(rec);
        }
        
        /**
         * 键名改名并扁平化 ,相当于 this.aoks2rec2(aliases).flat(null);<br>
         * 把一个 IRecord 给予扁平化:非递归式即只扁平化一层
         * 把 一个 order: <br>
         * REC("id",1,"product","苹果","user",REC("name","张三","sex","男"),"address",REC("city","上海","district","长宁区")); <br>
         * 转换成 <br>
         * REC("id",1,"product","苹果","user.name","张三","address.city","上海","address.district","长宁区");<br>
         * @param aliases 别名 键名的别名 <br>
         * sep 层级间的 分隔符号 默认为 "." <br>
         * @return 扁平化的 数据记录
         */
        default IRecord flat2(String aliases) {
            return this.flat2(aliases.split("[,\\\\/\\s]+"),null);
        }
        
        /**
         * 键名改名并扁平化 ,相当于 this.aoks2rec2(aliases).flat(sep);<br> 
         * 把一个 IRecord 给予扁平化:非递归式即只扁平化一层<br>
         * 把 一个 order: <br>
         * REC("id",1,"product","苹果","user",REC("name","张三","sex","男"),"address",REC("city","上海","district","长宁区")); <br>
         * 转换成 <br>
         * REC("id",1,"product","苹果","user.name","张三","address.city","上海","address.district","长宁区");<br>
         * @param aliases 别名 键名的别名 <br>
         * @param sep 层级间的 分隔符号 默认为 "." <br>
         * @return 扁平化的 数据记录
         */
        default IRecord flat2(String aliases, final String sep) {
            return this.flat2(aliases.split("[,\\\\/\\s]+"),sep);
        }
        
        /**
         * 键名改名并扁平化 ,相当于 this.aoks2rec2(aliases).flat(null);<br> 
         * 把一个 IRecord 给予扁平化:非递归式即只扁平化一层
         * 把 一个 order: <br>
         * REC("id",1,"product","苹果","user",REC("name","张三","sex","男"),"address",REC("city","上海","district","长宁区")); <br>
         * 转换成 <br>
         * REC("id",1,"product","苹果","user.name","张三","address.city","上海","address.district","长宁区");<br>
         * @param aliases 别名 键名的别名 <br>
         * sep 层级间的 分隔符号 默认为 "." <br>
         * @return 扁平化的 数据记录
         */
        default IRecord flat2(String aliases[]) {
            return this.flat2(aliases,null);
        }
        
        /**
         * 键名改名并扁平化 ,相当于 this.aoks2rec2(aliases).flat(sep);<br> 
         * 把一个 IRecord 给予扁平化:非递归式即只扁平化一层
         * 把 一个 order: <br>
         * REC("id",1,"product","苹果","user",REC("name","张三","sex","男"),"address",REC("city","上海","district","长宁区")); <br>
         * 转换成 <br>
         * REC("id",1,"product","苹果","user.name","张三","address.city","上海","address.district","长宁区");<br>
         * @param aliases 别名 键名的别名 <br>
         * @param sep 层级间的 分隔符号 默认为 "." <br>
         * @return 扁平化的 数据记录
         */
        default IRecord flat2(String aliases[], final String sep) {
            return this.aoks2rec2(aliases).flat(sep);
        }
        
        /**
         * 把一个 IRecord 给予扁平化:非递归式即只扁平化一层
         * 把 一个 order: <br>
         * REC("id",1,"product","苹果","user",REC("name","张三","sex","男"),"address",REC("city","上海","district","长宁区")); <br>
         * 转换成 <br>
         * REC("id",1,"product","苹果","user.name","张三","address.city","上海","address.district","长宁区");<br>
         * sep 层级间的 分隔符号 默认为 "." <br>
         * @return 扁平化的 数据记录
         */
        default IRecord flat() {
            return flat(null);
        }
        
        /**
         * 把一个 IRecord 给予扁平化:非递归式即只扁平化一层
         * 把 一个 order: <br>
         * REC("id",1,"product","苹果","user",REC("name","张三","sex","男"),"address",REC("city","上海","district","长宁区")); <br>
         * 转换成 <br>
         * REC("id",1,"product","苹果","user.name","张三","address.city","上海","address.district","长宁区");<br>
         * @param sep 层级间的 分隔符号 
         * @return 扁平化的 数据记录
         */
        default IRecord flat(final String sep) {
            final var separator = (sep == null) ? ".": sep; // 默认分隔符为 "."
            final var rec = this.stream().reduce(
                REC(), 
                (r,kvp) -> kvp.value() instanceof IRecord || kvp.value() instanceof Map
                    ? r.derive( kvp.value() instanceof Map
                            ? kvp.value2((Map<String,Object> p)->REC(p).aoks2rec(k->kvp.key()+separator+k))
                            : kvp.value2((IRecord p)->p.aoks2rec(k->kvp.key()+separator+k))
                      ) // 使用 kvp.key 作为前缀
                    : r.derive(kvp.key(),kvp.value()), // 直接加入
                    IRecord::derive);
            return rec;
        }
        
        /**
         * 把 一个IRecord节点 更换成 Node &lt; String &gt; <br>
         * rootName 根节点名称,默认为"root" <br>
         * valueKey KVPair的value 在 Node props中的键值名,默认为 :"value"<br>
         * @return 根节点  Node &lt; String &gt;
         */
        default Node<String> treeNode(){
            return this.treeNode(null, null);
        }
        
        /**
         * 把 一个IRecord节点 更换成 Node &lt; String &gt;
         * @param rootName 根节点名称，默认为:"root" <br>
         * @param valueKey KVPair的value 在 Node props中的键值名 ，默认为:"value"<br>
         * @return 根节点  Node &lt; String &gt;
         */
        default Node<String> treeNode(final String rootName, final String valueKey){
            return TREENODE(this,rootName,valueKey);
        }
        
        /**
         * IRececord 之间的比较大小,比较的keys选择当前对象的keys,当 null 小于任何值,即null值会排在牵头
         */
        @Override
        default int compareTo(final IRecord o) {
            if (o == null) return 1;
            if(this.keys().equals(o.keys())) {
                return IRecord.cmp(this.keys()).compare(this, o);
            }else {
                final var set = new LinkedHashSet<>(this.keys());
                set.addAll(o.keys());// 归并
                final var kk = set.stream().sorted().toArray(String[]::new);
                System.err.println("比较的两个个键名序列("+this.keys()+","+o.keys()+")不相同,采用归并键名序列进行比较:"+Arrays.deepToString(kk));
                return IRecord.cmp(kk,true).compare(this, o);
            }//if
        }
        
        /////////////////////////////////////////////////////////////////////
        // 以下是IRecord 的静态方法区域
        /////////////////////////////////////////////////////////////////////
        
         /**
         * 全连接连个rec1,rec2:返回一个 类型为{(key,(v1,v2)}的LinkedHashMap mm <br>
         * mm 中的key 与 rec1,rec2 中的key 相一致,可以这样理解mm是对rec1,rec2中的键值对儿按照key 进行分组，<br>
         * 每个分组是一个二元组,1号位置是rec1 中的元素 <br>
         * 2号位置是rec1中的元素，过rec1,rec2中没有对应与key的值,则对应key的值设置为null <br>
         * 
         * 全连接连个rec1,rec2 ,比如:<br>
         * var r1 = REC("1","A","2","B","4","D");<br>
         * var r2 = REC("1","a","2","b","3","c");<br>
         * var r3 = join(r1,r2);<br>
         * 返回：<br>
         * key tuple2
         * 1   A --> a <br>
         * 2   B --> b <br>
         * 4   D --> null <br>
         * 3   null --> c <br>
         * 
         * @param rec1 左边的记录(键值对儿集合)
         * @param rec2 右边的记录(键值对儿集合)
         * @return 连接后的连个字 {(key,(v1,v2)} 的集合，这是一个LinkedHashMap,是一个有序序列
         */
        static Map<String,Tuple2<Object,Object>> join(final IRecord rec1, final IRecord rec2){
            // mm 中的key 与 rec1,rec2 中的key 相一致,可以这样理解mm是对rec1,rec2中的键值对儿按照key 进行分组，每个分组是一个二元组,1号位置是rec1 中的元素
            // 2号位置是rec1中的元素，过rec1,rec2中没有对应与key的值,则对应key的值设置为null
            final var mm = new LinkedHashMap<String,Tuple2<Object,Object>>();// 返回值:{(key,(v1,v2)}
            
            if(rec1!=null)rec1.foreach((k,v)->{// 遍历第一个record:k 是键名,v是record中与k对应的值
                //tuple_value 是一个用于存放字段连接结果的 二元组,1号位置rec1中的数据,2号位置rec2中对应的数据。遍历rec1号时候2号位置不予设置
                mm.compute(k, (key,tuple_value)->{// key 与  k 是同一个值,
                    if(tuple_value==null)tuple_value=TUP2(v,null); // 初次创建,2号位置不予设置
                    else tuple_value._1(v);// 该键名位置窜在
                    return tuple_value; // 返回当前的值
                }); // 遍历MAP
            });// rec1.foreach
            
            if(rec2!=null)rec2.foreach((k,v)->{// 遍历第一个record:k 是键名,v是record中与k对应的值
                //tuple_value 是一个用于存放字段连接结果的 二元组,1号位置rec1中的数据,2号位置rec2中对应的数据。遍历rec2号时候1号位置不予设置
                mm.compute(k, (key,tuple_value)->{// key 与  k 是同一个值,
                    if(tuple_value==null)tuple_value = TUP2(null,v); // 初次创建,1号位置不予设置
                    else tuple_value._2(v); // 已经存在则修改原有的值
                    return tuple_value; // 返回当前的值
                });// 遍历MAP
            });// rec2.foreach
            
            return mm;
        }
        
        /**
        * 数据窗口滑动<br>
        * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
        * 
        * | size | 每个窗口大小为 size,每次移动的步长为step<br>
        * [1    2]<br>
        * step0:[2    3]<br>
        *   - step1:[3    4]<br>
        *   -   -   step2:[4]<br>
        * 返回:[  [1,2],  [2,3],  [3,4],  [4] ]<br>
        * 
        * @param <T> 元素类型
        * @param ll 待操作的列表
        * @param size 滑动的窗口大小
        * @param step 每次移动的步长
        * @return 滑动窗口的列表。
        */
       static <T> List<List<T>> sliding(final List<T> ll, final int size, final int step) {
           final int n = ll.size();
           final var aa = new ArrayList<>(ll);// 转换成数组类型
           final var res = new LinkedList<List<T>>();// 返回结果
           
           for(int i=0;i<n;i+=step) {
              final var from = i;// 开始位置
              final var to = i+size;// 结束位置
              final var sl = aa.subList(from, Math.min(to, n));// sublist
              res.add(sl);
           }//for
           
           return res;
       }
       
       /**
        * 数据窗口滑动<br>
        * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
        * 
        * | size | 每个窗口大小为 size,每次移动的步长为step<br>
        * [1    2]<br>
        * step0:[2    3]<br>
        *   - step1:[3    4]<br>
        *   -   -   step2:[4]<br>
        * 返回:[  [1,2],  [2,3],  [3,4],  [4] ]<br>
        * 
        * @param <T> 元素类型
        * @param ll 待操作的列表
        * @param size 滑动的窗口大小
        * @param step 每次移动的步长
        * @param b 是否过滤掉窗口大小不等于size的窗口,false 不过滤 ,true过滤,即 只返回 [[1,2],[2,3],[3,4]],把后面的残缺窗口 [4]舍弃
        * @return 滑动窗口的列表。
        */
       @SuppressWarnings("unchecked")
       static <T> List<T[]> sliding(final List<T> ll, final int size, final int step, final boolean b) {
           final int n = ll.size();
           final var aa = new ArrayList<>(ll);// 转换成数组类型
           final var res = new LinkedList<T[]>();// 返回结果
           final var componentType = ll.stream().filter(Objects::nonNull).findFirst()
                .map(e->(Class<T>)e.getClass()).orElse((Class<T>)Object.class);
           
           for(int i=0;i<n;i+=step) {
              final var from = i;// 开始位置
              final var to = i+size;// 结束位置
              final var sl = aa.subList(from, Math.min(to, n));// sublist
              if (b && sl.size() != size) break;
              res.add(sl.toArray(x->(T[])Array.newInstance(componentType,x)));
           }//for
           
           return res;
       }
       
       /**
        * 数据窗口滑动<br>
        * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
        * 
        * | size | 每个窗口大小为 size,每次移动的步长为step<br>
        * [1    2]<br>
        * step0:[2    3]<br>
        *   - step1:[3    4]<br>
        *   -   -   step2:[4]<br>
        * 返回:[  [1,2],  [2,3],  [3,4],  [4] ]<br>
        * 
        * @param <T> 元素类型
        * @param ll 待操作的列表
        * @param size 滑动的窗口大小
        * @param step 每次移动的步长
        * @return 滑动窗口的流
        */
       static <T> Stream<List<T>> slidingS(final List<T> ll, final int size, final int step) {
           return IRecord.sliding(ll, size, step).stream();
       }
       
       /**
       * 数据窗口滑动<br>
       * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
       * 
       * | size | 每个窗口大小为 size,每次移动的步长为step<br>
       * [1    2]<br>
       * step0:[2    3]<br>
       *   - step1:[3    4]<br>
       *   -   -   step2:[4]<br>
       * 返回:[  [1,2],  [2,3],  [3,4],  [4] ]<br>
       * 
       * @param <T> 元素类型
       * @param ll 待操作的列表
       * @param size 滑动的窗口大小
       * @param step 每次移动的步长
       * @param b 是否过滤掉窗口大小不等于size的窗口,false 不过滤 ,true过滤,即 只返回 [[1,2],[2,3],[3,4]],把后面的残缺窗口 [4]舍弃 
       * @return 滑动窗口的流
       */
      static <T> Stream<T[]> slidingS(final List<T> ll, final int size, final int step, final boolean b) {
          return IRecord.sliding(ll, size, step,b).stream();
      }
      
      /**
       * 数据窗口滑动<br>
       * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
       * 
       * | size | 每个窗口大小为 size,每次移动的步长为step<br>
       * [1    2]<br>
       * step0:[2    3]<br>
       *   - step1:[3    4]<br>
       *   -   -   step2:[4]<br>
       * 返回:[  [1,2],  [2,3],  [3,4],  [4] ]<br>
       * 
       * @param <T> 元素类型
       * @param tt 待操作的数据数组
       * @param size 滑动的窗口大小
       * @param step 每次移动的步长
       * @param b 是否过滤掉窗口大小不等于size的窗口,false 不过滤 ,true过滤,即 只返回 [[1,2],[2,3],[3,4]],把后面的残缺窗口 [4]舍弃 
       * @return 滑动窗口的流
       */
      static <T> Stream<T[]> slidingS(final T[] tt, final int size, final int step, final boolean b) {
          return IRecord.slidingS(Arrays.asList(tt), size, step,b);
      }
      
      /**
       * 数据窗口滑动<br>
       * 对一个:1 2 3 4,按照 size:为2,step为1的参数进行滑动的结果。<br>
       * 
       * | size | 每个窗口大小为 size,每次移动的步长为step<br>
       * [1    2]<br>
       * step0:[2    3]<br>
       *   - step1:[3    4]<br>
       *   -   -   step2:[4]<br>
       * 返回:[  [1,2],  [2,3],  [3,4],  [4] ]<br>
       * 
       * @param <T> 元素类型
       * @param stream 待操作的数据流
       * @param size 滑动的窗口大小
       * @param step 每次移动的步长
       * @param b 是否过滤掉窗口大小不等于size的窗口,false 不过滤 ,true过滤,即 只返回 [[1,2],[2,3],[3,4]],把后面的残缺窗口 [4]舍弃 
       * @return 滑动窗口的流
       */
      static <T> Stream<T[]> slidingS(final Stream<T> stream, final int size, final int step, final boolean b) {
          return IRecord.slidingS(stream.collect(Collectors.toList()), size, step,b);
      }
       
       /**
         * 把一个信息路径：path分解成各个组分结构的IRecord:kvp 定义为(路径位点key,路径信息元)：例如 :<br> 
         * (path:中国/辽宁/大连,  keys:["country","province","city"]),给变换成:
         * REC("country","中国","province","辽宁","city","大连") <br>
         * <br>
         * @param path 信息路劲,即具有层级的信息结构,是一个路径信息元（信息单元）的序列,比如：中国/辽宁/大连
         * @param delim path的分隔符
         * @param keys 路径层级的名称：每个阶层应该如何称谓，比如对于path:中国/辽宁/大连，
         *         第一层是国家，第二层是省份，第三层是城市，层级称谓keys就是[国家,省份,城市]
         * @return IRecord
         */
        static IRecord path2kvs(String path, String delim, String keys[]) {
            final var rec = REC();
            final var pp = path.split(delim);
            final var n = Math.min(keys.length,pp.length);
            Stream.iterate(0,i->i<n,i->i+1).forEach(i->rec.add(keys[i],pp[i+1]));
            return rec;
        }

        /**
         * 把一个信息路径：path分解成各个组分结构的IRecord:kvp 定义为(路径位点key,路径信息元)：例如 :<br> 
         * (path:中国/辽宁/大连,  keys:["country","province","city"]),给变换成:
         * REC("country","中国","province","辽宁","city","大连") <br>
         * <br>
         * @param path 信息路劲,即具有层级的信息结构,是一个路径信息元（信息单元）的序列,比如：中国/辽宁/大连
         * 信息单元的分隔符： delim 默认为 "[,/\\]+" <br> 
         * @param keys 路径层级的名称：每个阶层应该如何称谓，比如对于path:中国/辽宁/大连，
         * 第一层是国家，第二层是省份，第三层是城市，层级称谓keys就是[国家,省份,城市]
         * @return IRecord
         */
        static IRecord path2kvs(String path, String keys[]) {
            final var rec = REC();
            final var delim = "[,/\\\\]+";
            final var pp = path.split(delim);
            final var n = Math.min(keys.length,pp.length);
            Stream.iterate(0,i->i<n,i->i+1).forEach(i->rec.add(keys[i],pp[i+1]));
            return rec;
        }

        /**
         * 这是专门为pv2rec_eval 函数设计的值变换函数：所以采用采用value2kvs 而不是 obj2rec这样的名称。<br>
         * 把一个对象转换一个IRecord:kvs 是IRecord的别名与IRecord可以互换 <br>
         * 
         * 用指定的key 去构建一个Record,确保返回的结果中含有一个 名为key 键。<br>
         * 
         * @param value 值对象
         * @param key 值名称
         * @return IRecord IRecord 即键值对 kvs 
         */
        static IRecord value2kvs(Object value, String key) {
            if(value instanceof IRecord)return (IRecord)value;
            if(value instanceof Map)return REC( (IRecord)value);
            return REC(key,value);
        }

        /**
         * 这是专门为pv2rec_eval 函数设计的值变换函数：所以采用采用value2kvs 而不是 obj2rec这样的名称。<br>
         * 把一个对象转换陈一个IRecord:kvs 是IRecord的别名与IRecord可以互换<br>
         * 
         * @param value 值对象
         * @return IRecord 即键值对 kvs 
         */
        static IRecord value2kvs(Object value) {
                return value2kvs(value,"value");
        }

        /**
        * 层级信息的维护合并 path,value 计算 即 (path,value) 的变换为IRecord（键值对集合)<br>
        * 把 path 通过 pathkeys 进行变换<br>
        * 把value 通过value_key 进行变换<br>
        * 比如对于  (path:iphone6/苹果公司,value:6800) 进行pv2rec_eval("产品名/生产企业","价格") 计算 即:<br>
        * pv2rec_eval("产品名/生产企业","价格").apply("iphone6/苹果公司",6800);<br>
        * 就会返回：(产品名:iphone6,生产企业:苹果公司,价格:6800) 的一个IRecord 即kvs<br>
        * 
        * 使用示例：<br>
        * var r = res.dfs_eval_forone(pv2rec_eval("pct,vendor".split(","),"value"));<br>
        * path,value 转record 的 计算器 <br>
        * 
        * @param pathkeys 路径 keys, 使用"[,/\\\\]+"进行分割 
        * @param value_key 值 的key名
        * @return BiFunction<String,Object,IRecord>
        */
       static BiFunction<String,Object,IRecord> pv2rec_eval(
               final String pathkeys, String value_key) {
           return pv2rec_eval(pathkeys.split("[,/\\\\]+"),value_key);
       }
       
       /**
        * 层级信息的维护合并 path,value 计算 即 (path,value) 的变换为IRecord（键值对集合)<br>
        * 把 path 通过 pathkeys 进行变换<br>
        * 把value 通过value_key 进行变换<br>
        * 比如对于  (path:iphone6/苹果公司,value:6800) 进行pv2rec_eval("产品名/生产企业","价格") 计算 即:<br>
        * pv2rec_eval("产品名/生产企业","价格").apply("iphone6/苹果公司",6800);<br>
        * 就会返回：(产品名:iphone6,生产企业:苹果公司,价格:6800) 的一个IRecord 即kvs<br>
        * 
        * 使用示例：<br>
        * var r = res.dfs_eval_forone(pv2rec_eval("pct,vendor".split(","),"value"));<br>
        * path,value 转record 的 计算器 <br>
        * 
        * @param pathkeys 路径 keys 对层级信息(path)进行分解：维度分解的键名序列
        * @param value_key 值 key 值键名
        * @return BiFunction<String,Object,IRecord> 一个 path,value 转record 的 计算器
        */
        static BiFunction<String,Object,IRecord> pv2rec_eval(
                final String[] pathkeys, String value_key) {
            return (path,value)->{
                var rec = REC();
                rec.add(path2kvs(path,pathkeys)); // 路径信息转换成 IRecord 键值对儿
                rec.add(value2kvs(value,value_key)); // value 信息转换成键值对儿
                return rec;
            };
        }
        
        /**
         * 遍历IRecord 深度遍历  <br>
         * 
         * @param rec 遍历的对象
         * @param cs biCONSumer 回调函数, 即KV值的处理函数( key,values), 需要注意cons是一个二元函数。
         * key 是指节点的路径信息; values 是指与key所对应的值的*集合*：这个集合是Stream 类型的；
         * 之所以采用Stream来封装值数据，是为统一单值与集合(Collection)类型的值数据。stream 读一下只返回一个值。单值与多值是一样的。
         * @param prefix 键值的前缀,null表示"/"，即根节点
         * @param delim 层级分隔符号,null表示"/"
         */
        @SuppressWarnings("unchecked")
        static void dfs(final IRecord rec, final BiConsumer<String, Stream<Object>> cs,
                        final String prefix, final String delim) {
            final var default_prefix = "/";// 默认的根前缀（第0基层的前缀）
            final var default_delim = "/";// 默认的阶层分隔符号
            final var final_prefix = (prefix==null?default_prefix:prefix);// 生成可用的不可变对象
            final var final_delim = (delim==null?default_delim:delim);// 生成可用的不可变对象
            final Function<String,String> new_prefix = (k)->{// 更具节点名称(key)生成下一阶层的名称前缀。
                var d = ((default_prefix.equals(final_prefix))?"":final_delim);
                return final_prefix+d+k; // 新的阶层前缀。
            };
                
            rec.foreach((k,v)->{
                Stream<Object> stream = null;// 流是对单值对象与Collection的统一描述。这是dfs所规定的默认数据）数值的访问方法。
                if(v instanceof Collection) {// 集合类型给予展开
                    stream = ((Collection<Object>)v).stream();
                }else if(v instanceof IRecord) {
                    dfs((IRecord)v,cs,new_prefix.apply(k),null);// 修改前缀，递归进入更深一层
                }else if(v instanceof Map) {
                    var r = REC();// 把map  转换成 IRecord
                    ((Map<Object,Object>)v).forEach((key,value)->r.add(key.toString(),value));
                    if(r.size()>0)dfs(r,cs,new_prefix.apply(k),delim) ;// 修改前缀，递归进入更深一层
                    else stream = new LinkedList<>().stream(); // 空值列表
                }else {// 默认对象绑定。
                    stream = v instanceof Stream?(Stream<Object>)v: Stream.of(v);// 生成一个单值的流
                }// if
                
                // 回调函数处理
                if(stream!=null)cs.accept(new_prefix.apply(k),stream);
            });// record 对象遍历
        }
        
        /**
         * SUPplier<LinkedList>的一个简写：这是一个容器生运算符 <br>
         * 生成一个 列表：使用示例 <br>
         * e.collect(supll(Object.class), 
         *  (List<Object>aa, KVPair<String,Object>a)->{aa.add( MFT( "{0}[{1}]", a.key(),a.value() ) );}, <br>
         *  cbll(Object.class) <br>
         * ).stream().map(f->f+"").collect(Collectors.joining("*")), <br>
         *   
         * @param <R> 容器中的元素的类型 
         * @param clazz 容器中的元素的类型的class
         * @return 新建列表
         */
        static <R> Supplier<List<R>> supll(Class<R> clazz){
            return LinkedList::new;
        }
        
        /**
         * ComBiner<LinkedList> 的一个简写：这是一个操作运算符
         * e.collect(supll(Object.class), 
         *  (List<Object>aa, KVPair<String,Object>a)->{aa.add( MFT( "{0}[{1}]", a.key(),a.value() )   );},
         *   cbll(Object.class)
         *  ).stream().map(f->f+"").collect(Collectors.joining("*")),
         *  
         * @param <R> 容器中的元素的类型
         * @param clazz 容器中的元素的类型的class
         * @return 新列表
         */
        static <R> BinaryOperator<List<R>> cbll(Class<R> clazz){
            return (List<R> aa,List<R>bb)->{aa.addAll(bb);return aa;};
        }
           
        /**
         * 把一个键值对的数据转换成一个R的类型
         * 
         * @param <R> 容器中的元素的类型
         * @param obj2r 把键值对儿kv 转换成 目标对象R的函数
         * @return R类型的数据对象
         */
        static <R> Function<KVPair<String,Object>,R> kv2r(final Function<Object, R> obj2r){
            return (kv)->obj2r.apply(kv.value());
        }
        
        /**
         * 合并两个 Record：即这个一个按照键名对连个 键值对儿集合进行 的 并集操作。
         * 
         * @param rec1 IRecord 记录1
         * @param rec2 IRecord 记录2
         * @param rec2_appendto_rec1 是否把 rec2 追加到rec1, 是 追加,否 合并  生成了一个新的对象。
         * @return 合并了rec1 和 rec2 两个记录内容键值儿 后的Record
         */
        static IRecord union(final IRecord rec1, final IRecord rec2, final boolean rec2_appendto_rec1) {
            var rec = rec2_appendto_rec1 ? rec1 : REC();
            if(rec1!=null && rec!=rec1) rec1.foreach(rec::add);
            if(rec2!=null) rec2.foreach(rec::add);
            return rec;
        }

        /**
         * 格式化记录列表
         * @param recs 记录列表
         * @return 格式化记录列表
         */
        static String format(final List<IRecord> recs) {
            return format(recs,"\t");
        }
        
        /**
         * 格式化记录列表
         * @param recs 记录列表
         * @param sep 分隔符
         * @return 格式化记录列表
         */
        static String format(final List<IRecord> recs, final String sep) {
            final StringBuilder buffer = new StringBuilder();
            @SuppressWarnings("unused")
            final var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            if(recs==null)return "";
            int n = recs.size();
            List<String> hh = new ArrayList<>(n);// 表头字段顺序
            for(int i=0;i<n;i++){
                if(i==0) {
                    IRecord r = recs.get(0);
                    buffer.append(recs.get(i).stream().map(kv -> kv.key() + "")
                            .collect(Collectors.joining(sep))).append("\n");
                    hh = MAP(r.kvs(), KVPair::key);//只提取第一个记录的结构字段
                }//if
                
                final StringBuilder line = new StringBuilder();
                // 之所以使用 hh,而不是kvs collect joining 是为了保持异质的record 集合。即里那个中不同结构的record混合list
                for(var h:hh) {
                    var obj = recs.get(i).get(h);
                    if(obj==null) obj = "(null)";// 空数值变换
                    line.append(obj).append(sep);
                }
                buffer.append(line.toString().trim()).append("\n");
            }//for
            return buffer.toString();
        }
        
        /**
         * 格式化数据对象
         * 
         * @param recs IRecord 列表
         * @return 格式化数据对象
         */
        static String FMT(final List<IRecord> recs) {
            return format(recs);
        }
        
        /**
         * 格式化数据对象,带有行号的格式化
         * 
         * @param recs IRecord 列表
         * @return 带有行号的格式化
         */
        static String FMT2(final List<IRecord> recs) {
           final var line =  format(recs);
           final var seed = new AtomicLong(0L);// 行号生成器的种子
           final Supplier<String> rownum = ()->{// 行号生成器
               final var n = seed.getAndIncrement();
               return n==0 ? "#" : n+"";// 行号生成器
           };
           return JOIN( Arrays.stream(line.split("\n")).map(e->MFT("{0}\t{1}",rownum.get(),e)),// 行格式化
                   "\n");// JOIN 行连接
        }

        /**
         * 格式化数据对象
         * 
         * @param recs IRecord 列表
         * @param sep 行内分隔符
         * @return 格式化数据对象
         */
        static String FMT2(final List<IRecord> recs, final String sep) {
            return format(recs,sep);
        }

        /**
         * 获取指定Class的字段列表
         * @param clsu 类对象
         * @return clsu的字段列表
         */
        static <U> Map<String,Field> FIELDS(final Class<U> clsu) {
            Map<String,Field> map = new LinkedHashMap<>();
            Arrays.stream(clsu.getDeclaredFields()).forEach(e-> map.put(e.getName(), e));
            return map;
        }

        /**
         * 把一个java object的值类型 转换成 获取对应SQL类型
         * @return obj对应的SQL数据类型。
         */
        static String OBJ2SQLTYPE(final Object obj) {
            return OBJ2SQLTYPE(obj,null);
        }
        
        /**
         * 把对象转换成key->value对儿
         * @param obj 数据对象
         * @return key->value对儿集合的IRecord
         */
        static IRecord OBJ2REC(final Object obj){
            return OBJ2REC(obj,(Predicate<Field>)null);
        }
        
        /**
         * 把对象转换成key->value对儿
         * @param obj 数据对象
         * @param pfilter 字段过滤,只返回返回结果为true的结果字段.
         * @return key->value对儿
         */
        static IRecord OBJ2REC(final Object obj, final Predicate<Field> pfilter){
            return REC(OBJ2KVS(obj,pfilter==null?(t)->true:pfilter));
        }
        
        /**
         * 把对象转换成key->value对儿
         * @param obj 数据对象
         * @param keys 字段过滤数组,只返keys中字段.
         * @return key->value对儿
         */
        static IRecord OBJ2REC(final Object obj, String keys[]){
            final var kk = Arrays.asList(keys);
            return REC(OBJ2KVS(obj,e->kk.contains(e.getName())));
        }
        
        /**
         * 把对象转换成key->value对儿
         * @param obj 数据对象
         * @param keys 字段过滤,只返keys中字段. keys 中采用"[,\\s，/\\\\]+"的分隔符进行分隔。 
         * @return key->value对儿
         */
        static IRecord OBJ2REC(final Object obj, String keys){
            final var kk = Arrays.asList(keys.split("[,\\s，/\\\\]+"));
            return REC(OBJ2KVS(obj,e->kk.contains(e.getName())));
        }
        
        /**
         * java反射bean的get方法
         * 
         * @param clazz 类名
         * @param fieldName 属性名
         * @return getter 方法
         */
        @SuppressWarnings({ "unchecked", "rawtypes" })
        public static Method getGetter(final Class clazz, final String fieldName) {
            StringBuilder sb = new StringBuilder();
            sb.append("get").append(fieldName.substring(0, 1).toUpperCase()).append(fieldName.substring(1));
            try {
                Class[] types = new Class[] {};
                return clazz.getMethod(sb.toString(), types);
            } catch (Exception e) {
                //e.printStackTrace();
            }
            return null;
        }
        
        /**
         * java反射bean的set方法
         * 
         * @param clazz 类名
         * @param fieldName 字段名
         * @return setter 方法
         */
        @SuppressWarnings({ "unchecked", "rawtypes" })
        public static Method getSetter(final Class clazz, final String fieldName) {
            try {
                Class[] parameterTypes = new Class[1];
                Field field = clazz.getDeclaredField(fieldName);
                parameterTypes[0] = field.getType();// 返回参数类型
                StringBuilder sb = new StringBuilder();
                sb.append("set").append(fieldName.substring(0, 1).toUpperCase()).append(fieldName.substring(1));
                Method method = clazz.getMethod(sb.toString(), parameterTypes);
                return method;
            } catch (Exception e) {
                //e.printStackTrace();
            }
            return null;
        }
        
        /**
         * 把对象转换成key->value对儿<br>
         * 分解一个对象obj成为键值对儿集合即IRecord 记录。
         * 
         * @param obj 待分解的数据对象
         * @param pfilter 字段过滤,只返回返回结果为true的结果字段. 当pfilter 为null 不对字段进行过滤。
         * @return 键值对儿集合
         */
        static Map<String, Object> OBJ2KVS(final Object obj, final Predicate<Field> pfilter) {
            final var mm = new LinkedHashMap<String, Object>();
            final Predicate<Field> _pfilter = pfilter == null ? e -> true : pfilter;
            final var clazz = obj.getClass();

            if (obj != null) {
                Arrays.stream(clazz.getDeclaredFields()).filter(_pfilter).forEach(fld -> {
                    final var getter = getGetter(clazz, fld.getName()); // 提取getter方法
                    Object v = null;
                    if (getter != null) {// 优先尝试使用getter方法进行数据读取
                        try {v = getter.invoke(obj, (Object[]) null);} catch (Exception ignored) {}
                    } else { // 读取不到getter方法而后才进行字段直接读取
                        fld.setAccessible(true); // 加入字段直接访问方法
                        try {v = fld.get(obj);} catch (Exception ignored) {}
                    }// if
                    mm.put(fld.getName(), v);
                }); // forEach
            } // obj!=null 

            return mm;
        }
        
        /**
         * 用inits初始化对象obj
         * 数据初始化,使用 inits 来初始化对象obj,用inits中的key的值设置obj中的对应的字段 
         * @param objClass 待初始对象的类型class
         * @param inits 初始源数据
         * @return T 类型的结果
         */
        static<T> T OBJINIT(final Class<T> objClass, final IRecord inits) {
            if(objClass==null||inits==null)return null;
            return OBJINIT(objClass,inits.toMap());
        }
        
        /**
         * 用inits初始化obj
         * 数据初始化,使用 inits 来初始化对象obj,用inits中的key的值设置obj中的对应的字段 
         * @param objClass 待初始对象的类型class
         * @param inits 初始源数据
         * @return T 类型的结果
         */
        static<T> T OBJINIT(final Class<T> objClass, final Map<String, Object> inits) {
            if(inits==null)return null;
            T obj = null;
            try {
                obj = objClass.getConstructor((Class[])null).newInstance((Object[])null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if(obj==null)return null;
            return OBJINIT(obj,inits);
        }
        
        /**
         * 用inits初始化对象obj
         * 数据初始化,使用 inits 来初始化对象obj,用inits中的key的值设置obj中的对应的字段 
         * @param obj 待初始对象
         * @param inits 初始源数据
         * @return T 类型的结果
         */
        static<T> T OBJINIT(final T obj, final IRecord inits) {
            if(inits==null||obj==null)return null;
            return OBJINIT(obj,inits.toMap());
        }
        
        /**
         * 数据初始化,使用 inits 来初始化对象obj,用inits中的key的值设置obj中的对应的字段:带有简单的类型转换功能 
         * @param obj 待初始对象
         * @param inits 初始源数据
         * @param <T> 待初始化的对象的类型
         * @return T 类型的结果
         */
        static<T> T OBJINIT(final T obj, final Map<String, ?> inits) {
            
            Arrays.stream(obj.getClass().getDeclaredFields()) // 依次处目标对象结构的各个字段属性
            .filter(e-> inits.containsKey(e.getName())).forEach(fld->{// 字段数值的设置
                try {
                    fld.setAccessible(true);
                    final Object value=inits.get(fld.getName());
                    if(value==null)return;
                    
                    /*基本类型与包裹类之间的转换*/{
                        // 这里关于类型的转换没有一个好的实现办法，目前来看只能一个的写出来。
                        final Class<?> src = value.getClass();// 源类型
                        final Class<?> target = fld.getType();// 目标类型
                        //System.out.println(fld.getName()+"("+value+")["+target+"<-"+src+"]");
                        if( (target ==int.class||target == Integer.class) && 
                            (src == Long.class || src == long.class) ) { // 长整类型换 整型
                            fld.set(obj,((Long)value).intValue());return;
                        }
                        if( (target ==long.class||target == Long.class) && 
                            (src == int.class || src == Integer.class) ) { // 长整类型换 整型
                            fld.set(obj,((Number)value).longValue());return;
                        }
                        
                        // 从timestamp 转换为其他类型
                        if(src==Timestamp.class && target==Date.class){// Timestamp -> Date
                            final Date d = ((Timestamp)value);
                            fld.set(obj,d);return;
                        }else if(src==Timestamp.class && target==LocalDate.class){// Timestamp -> LocalDate
                            final Date d = ((Timestamp)value);
                            fld.set(obj,CronTime.dt2ld(d));return;
                        }else if(src==Timestamp.class && target==LocalDateTime.class){// Timestamp -> LocalDateTime
                            final Date d = ((Timestamp)value);
                            fld.set(obj,CronTime.dt2ldt(d));return;
                        }else if(src==Timestamp.class && target==LocalTime.class){// Timestamp -> LocalTime
                            final Date d = ((Timestamp)value);
                            fld.set(obj,CronTime.dt2lt(d));return;
                        }
                        
                        if(src==Date.class && target==Timestamp.class){// Date->Timestamp
                            final Timestamp d =new Timestamp(((Date) value).getTime());
                            fld.set(obj,d);return;
                        }else if(src==LocalDateTime.class && target==Timestamp.class){// LocalDateTime->Timestamp
                            final Timestamp d =new Timestamp(CronTime.ldt2dt((LocalDateTime)value).getTime());
                            fld.set(obj,d);return;
                        }else if(src==LocalDate.class && target==Timestamp.class){// LocalDateTime->Timestamp
                            final Timestamp d =new Timestamp(CronTime.ld2dt((LocalDate)value).getTime());
                            fld.set(obj,d);return;
                        }else if(src==LocalTime.class && target==Timestamp.class){// LocalDateTime->Timestamp
                            final Timestamp d =new Timestamp(CronTime.lt2dt((LocalTime)value).getTime());
                            fld.set(obj,d);return;
                        }
                    }// /*基本类型与包裹类之间的转换*/
                    
                    if(fld.getType() == value.getClass()) {
                        fld.set(obj,value);
                    }else if (value instanceof String){// 对字符串类型尝试做类型转换
                        if(fld.getType()==Character.class || fld.getType()==char.class) {// 数字
                            fld.set(obj, (value.toString().charAt(0)));
                        } else if(fld.getType()==Integer.class || fld.getType()==int.class) {// 数字
                            fld.set(obj, ((Double)Double.parseDouble(value.toString())).intValue());
                        } else if(fld.getType()==Double.class || fld.getType()==double.class) {// 数字
                            fld.set(obj, Double.parseDouble(value.toString()));
                        } else if(fld.getType()==Float.class || fld.getType()==float.class ) {// 数字
                            fld.set(obj, Float.parseFloat(value.toString()));
                        } else if(fld.getType()==Short.class || fld.getType()==short.class) {// 数字
                            fld.set(obj, Short.parseShort(value.toString()));
                        }  else if(fld.getType()==Boolean.class || fld.getType()==boolean.class) {// 数字
                            fld.set(obj, Boolean.parseBoolean(value.toString()));
                        } else if(fld.getType()==Long.class || fld.getType()==long.class) {// 数字
                            fld.set(obj, ((Number)Double.parseDouble(value.toString())).longValue());
                            //System.out.println(obj+"===>"+value);
                        } else if(fld.getType() == Date.class||
                            fld.getType() == LocalDate.class ||
                            fld.getType() == LocalDateTime.class||
                            fld.getType() == LocalTime.class) {// 时间类型的处理。
                            
                            Date date = null;// 日期对象
                            if(value instanceof Number) {
                                final long time = ((Number)value).longValue();
                                date = new Date(time);
                            } else {
                                final String ss[] = "yyyy-MM-dd HH:mm:ss,yyyy-MM-dd HH:mm,yyyy-MM-dd HH,yyyy-MM-dd,yyyy-MM,yyyy-MM,yyyy"
                                    .split("[,]+");
                                for(String s:ss) {
                                    try {date = new SimpleDateFormat(s).parse(value.toString());}catch(Exception ignored) {};
                                    if(date!=null)break;
                                }//for
                            }// if( value instanceof Number
                            // 设置时间字段
                            
                            if(fld.getType() == LocalDate.class) {// LocalDate
                                fld.set(obj,CronTime.dt2ld(date));
                            }else if(fld.getType() == LocalDateTime.class) {// LocalDateTime
                                fld.set(obj,CronTime.dt2ldt(date));
                            }else if(fld.getType() == LocalTime.class) {// LocalTime
                                fld.set(obj,CronTime.dt2lt(date));
                            }else {
                                fld.set(obj,date);
                            }// if(fld.getType() == LocalDate.class) 
                            
                        }// else if(fld.getType() == Date.class)
                        
                    }// if(fld.getType() == value.getClass())
                }catch(Exception ex) {ex.printStackTrace();}
            });// forEach(fld
            
            return obj;
        }// OBJINIT

        /**
         * 把一个java object的值类型 转换成 获取对应SQL类型
         * @param size 类型的尺寸大小
         * @return 把一个java object的值类型 转换成 获取对应SQL类型
         */
        static String OBJ2SQLTYPE(final Object obj, final Integer size) {
            if(obj==null)return null;
            Class<?> cls = null;
            cls = (obj instanceof Class<?>)?(Class<?>)obj:obj.getClass();
            final var mm= new HashMap<Object,String>();
            mm.put(byte.class, "char(1)");mm.put(Byte.class, "char(1)");
            mm.put(char.class, "int");mm.put(Character.class, "int");
            mm.put(int.class, "int");mm.put(Integer.class, "int");
            mm.put(long.class, "long");mm.put(Long.class, "long");
            mm.put(short.class, "int");mm.put(Short.class, "int");
            mm.put(double.class, "double");mm.put(Double.class, "double");
            mm.put(float.class, "double");mm.put(float.class, "double");
            mm.put(boolean.class, "tinyint(1)");mm.put(boolean.class, "tinyint(1)");
            if(size!=null && cls == String.class )
                mm.put(String.class, "varchar("+size+")");
            else
                mm.put(String.class, "TEXT");
            mm.put(StringBuffer.class, "TEXT");
            mm.put(Date.class, "timestamp");
            
            return mm.get(cls);
        }
        
        /**
         * 具体了的REC函数的实现：为了保证REC的美观性与不限定参数的性质。
         * 标准版的记录生成器, map 生成的是LinkedRecord
         * @param kvs 键值序列: key1,value1,key2,value2,....
         * @return IRecord对象
         */
        static IRecord _REC(final Object[] kvs) {
            final LinkedRecord rec = new LinkedRecord();
            if(kvs==null)return rec;
            if(kvs.length==1) {// 单个元素
                final Object o = kvs[0];
                return (o!=null && o instanceof Map)// (key,value) 序列
                ? LinkedRecord.of((Map<?,?>)o)
                : rec;
            }
            
            for(int i=0;i<kvs.length;i+=2) {
                String key = kvs[i]==null?"null":kvs[i].toString();// 键值名
                Object value = (i+1)<kvs.length?kvs[i+1]:null;//如果最后一位是key则它的value为null
                rec.data.put(key, value);
            }//for
            
            return rec;
        }
        
        /**
         * 标准版的记录生成器, map 生成的是LinkedRecord
         * 
         * @param map 键值映射,键名会调用掉map键的toString 来给予生成。
         * @return IRecord对象
         */
        static IRecord REC(final Map<?, ?> map) {
            final LinkedRecord rec = new LinkedRecord();
            map.forEach((k, v) -> rec.data.put(k == null ? "null" : k.toString(), v));
            return rec;
        }

        /**
         * 标准版的记录生成器, map 生成的是LinkedRecord
         * 
         * @param kvs 键,值序列:key0,value0,key1,value1,....
         * @return IRecord对象
         */
        static IRecord REC(final Object... kvs) {
            return _REC(kvs);
        }
        
        /**
         * 把一个键值对儿
         * 
         * @param kvps 键值对儿序列 [(key0,value0),(key1,value1),...]
         * @return IRecord 结果记录
         */
        @SafeVarargs
        static IRecord REC(final KVPair<String, Object>... kvps) {
            final var rec = new LinkedRecord();
            Stream.of(kvps).forEach(p -> rec.add(p.key(), p.value()));
            return rec;
        }

        /**
         * 把一个键值对儿
         * 
         * @param kvps 键值对儿序列 [(key0,value0),(key1,value1),...]
         * @return IRecord 结果记录
         */
        static IRecord REC(final List<KVPair<String, Object>> kvps) {
            final var rec = new LinkedRecord();
            kvps.forEach(p -> rec.add(p.key(), p.value()));
            return rec;
        }
        
        /**
         * 把一个扁平结构的 recs 转换成一个层级结构的IRecord <br>
         * 
         * 示例:<br>
         * REC3(REC("a/b/c",123,"a/b/d",456),REC("e/f",7,"g",8)).dfs_forone((p,v)->{<br>
         *  System.out.println(p+"--->"+v); <br>
         * });<br>
         * 结构如下:<br>
         * /g--->8 <br>
         * /a/b/c--->123 <br>
         * /a/b/d--->456 <br>
         * /e/f--->7 <br>
         * <br>
         * 注意:<br>
         * 不同Record 之间的同名键名 会彼此覆盖:比如 REC3(REC("a",123,"a/b/c",234)). <br>
         * REC3(REC("a",123,"a/b/c",234)).dfs_forone((p, v) -> { <br>
         *   System.out.println(p + "--->" + v); <br>
         * }); <br>
         * 会只生成 /a/b/c--->234 一条记录。原因是 "a"的123被"a/b/c" 给覆盖掉了。<br>
         * a/b/c 表示 a是一个复合结构，因此 原来的 单值 123,就被替换换。<br>
         * 即 一个层级节点：只能要么是 复合节点，要么是单值节点 不能二者兼具。
         * <br>
         * REC3(REC("a",1),REC("a",2)) 会把 同名的key 合并在一起:值别拼接到一个数组中。即  a:[1,2]  <br>
         * 示例代码: <br>
         * final var s = S(REC("a/b/c",123,"a",98),REC("a/b/c",123,"a/x",98)); <br>
         * System.out.println(HIERACHIES(s,REC(),"/")); <br>
         * 输出:a:x:98   b:c:[123, 123] <br>
         * <br>
         * 
         * 生成IRecord记录
         * @param recs IRecord记录集合 <br>
         * initrec 初始化 record 默认为 REC
         * @return IRecord
         */
        static IRecord REC3(final IRecord... recs) {
            return REC3(Arrays.stream(recs),REC());
        }
        
        /**
         * 把一个扁平结构的 recs 转换成一个层级结构的IRecord <br>
         * 示例:<br>
         * REC3(L(REC("a/b/c",123,"a/b/d",456),REC("e/f",7,"g",8))).dfs_forone((p,v)->{ <br>
         *  System.out.println(p+"--->"+v); <br>
         * });<br>
         * 结构如下:<br>
         * /g--->8 <br>
         * /a/b/c--->123 <br>
         * /a/b/d--->456 <br>
         * /e/f--->7 <br>
         * <br>
         * 注意:<br>
         * 不同Record 之间的同名键名 会彼此覆盖:比如 REC3(REC("a",123,"a/b/c",234)). <br>
         * REC3(REC("a",123,"a/b/c",234)).dfs_forone((p, v) -> { <br>
         *   System.out.println(p + "--->" + v); <br>
         * }); <br>
         * 会只生成 /a/b/c--->234 一条记录。原因是 "a"的123被"a/b/c" 给覆盖掉了。<br>
         * a/b/c 表示 a是一个复合结构，因此 原来的 单值 123,就被替换换。<br>
         * 即 一个层级节点：只能要么是 复合节点，要么是单值节点 不能二者兼具。<br>
         * 
         * <br>
         * REC3(REC("a",1),REC("a",2)) 会把 同名的key 合并在一起:值别拼接到一个数组中。即  a:[1,2]  <br>
         * 示例代码: <br>
         * final var s = S(REC("a/b/c",123,"a",98),REC("a/b/c",123,"a/x",98)); <br>
         * System.out.println(HIERACHIES(s,REC(),"/")); <br>
         * 输出:a:x:98   b:c:[123, 123] <br>
         * <br>
         * 
         * @param recs IRecord记录 集合 <br>
         * initrec 初始化 record 默认为 REC
         * @return IRecord
         */
        static IRecord REC3(final List<IRecord> recs) {
            return REC3(recs.stream(),REC());
        }
        
        /**
         * 把一个扁平结构的 recs 转换成一个层级结构的IRecord <br>
         * 示例:<br>
         * var rec = REC("a/b/c",123,"a/b/d",456,"e/f",7,"g",8); <br>
         * REC3(rec,REC()).dfs_forone((p,v)->{<br>
         *  System.out.println(p+"--->"+v); <br>
         * });<br>
         * 结构如下:<br>
         * /g--->8 <br>
         * /a/b/c--->123 <br>
         * /a/b/d--->456 <br>
         * /e/f--->7 <br>
         * 
         * <br>
         * 注意:<br>
         * 不同Record 之间的同名键名 会彼此覆盖:比如 REC3(REC("a",123,"a/b/c",234)). <br>
         * REC3(REC("a",123,"a/b/c",234)).dfs_forone((p, v) -> { <br>
         *   System.out.println(p + "--->" + v); <br>
         * }); <br>
         * 会只生成 /a/b/c--->234 一条记录。原因是 "a"的123被"a/b/c" 给覆盖掉了。<br>
         * a/b/c 表示 a是一个复合结构，因此 原来的 单值 123,就被替换换。<br>
         * 即 一个层级节点：只能要么是 复合节点，要么是单值节点 不能二者兼具。<br>
         * 
         * <br>
         * REC3(REC("a",1),REC("a",2)) 会把 同名的key 合并在一起:值别拼接到一个数组中。即  a:[1,2]  <br>
         * 示例代码: <br>
         * final var s = S(REC("a/b/c",123,"a",98),REC("a/b/c",123,"a/x",98)); <br>
         * System.out.println(HIERACHIES(s,REC(),"/")); <br>
         * 输出:a:x:98   b:c:[123, 123] <br>
         * <br>
         * 
         * 生成IRecord记录
         * @param recs IRecord记录集合流
         * @param initrec 初始化 record
         * @return IRecord
         */
        static IRecord REC3(final List<IRecord> recs, final IRecord initrec) {
            return REC3(recs.stream(),initrec);
        }
        
        /**
         * 把一个扁平结构的 recs 转换成一个层级结构的IRecord <br>
         * 示例:<br>
         * var rec = REC("a/b/c",123,"a/b/d",456,"e/f",7,"g",8); <br>
         * REC3(rec,REC()).dfs_forone((p,v)->{ <br>
         *  System.out.println(p+"--->"+v); <br>
         * });<br>
         * 结构如下:<br>
         * /g--->8 <br>
         * /a/b/c--->123 <br>
         * /a/b/d--->456 <br>
         * /e/f--->7 <br>
         * 
         * <br>
         * 注意:<br>
         * 不同Record 之间的同名键名 会彼此覆盖:比如 REC3(REC("a",123,"a/b/c",234)). <br>
         * REC3(REC("a",123,"a/b/c",234)).dfs_forone((p, v) -> { <br>
         *   System.out.println(p + "--->" + v); <br>
         * }); <br>
         * 会只生成 /a/b/c--->234 一条记录。原因是 "a"的123被"a/b/c" 给覆盖掉了。<br>
         * a/b/c 表示 a是一个复合结构，因此 原来的 单值 123,就被替换换。<br>
         * 即 一个层级节点：只能要么是 复合节点，要么是单值节点 不能二者兼具。<br>
         * 
         * <br>
         * REC3(REC("a",1),REC("a",2)) 会把 同名的key 合并在一起:值别拼接到一个数组中。即  a:[1,2]  <br>
         * 示例代码: <br>
         * final var s = S(REC("a/b/c",123,"a",98),REC("a/b/c",123,"a/x",98)); <br>
         * System.out.println(HIERACHIES(s,REC(),"/")); <br>
         * 输出:a:x:98   b:c:[123, 123] <br>
         * <br>
         * 
         * 生成IRecord记录
         * @param recsStream IRecord记录
         * @return 层级结构的IRecord
         */
        static IRecord REC3(final Stream<IRecord> recsStream) {
            return REC3(recsStream,REC(),null);
        }
        
        /**
         * 把一个扁平结构的 recs 转换成一个层级结构的IRecord <br>
         * 示例:<br>
         * var rec = REC("a/b/c",123,"a/b/d",456,"e/f",7,"g",8); <br>
         * REC3(rec,REC()).dfs_forone((p,v)->{ <br>
         *  System.out.println(p+"--->"+v); <br>
         * });<br>
         * 结构如下:<br>
         * /g--->8 <br>
         * /a/b/c--->123 <br>
         * /a/b/d--->456 <br>
         * /e/f--->7 <br>
         * 
         * <br>
         * 注意:<br>
         * 不同Record 之间的同名键名 会彼此覆盖:比如 REC3(REC("a",123,"a/b/c",234)). <br>
         * REC3(REC("a",123,"a/b/c",234)).dfs_forone((p, v) -> { <br>
         *   System.out.println(p + "--->" + v); <br>
         * }); <br>
         * 会只生成 /a/b/c--->234 一条记录。原因是 "a"的123被"a/b/c" 给覆盖掉了。<br>
         * a/b/c 表示 a是一个复合结构，因此 原来的 单值 123,就被替换换。<br>
         * 即 一个层级节点：只能要么是 复合节点，要么是单值节点 不能二者兼具。<br>
         * 
         * <br>
         * REC3(REC("a",1),REC("a",2)) 会把 同名的key 合并在一起:值别拼接到一个数组中。即  a:[1,2]  <br>
         * 示例代码: <br>
         * final var s = S(REC("a/b/c",123,"a",98),REC("a/b/c",123,"a/x",98)); <br>
         * System.out.println(HIERACHIES(s,REC(),"/")); <br>
         * 输出:a:x:98   b:c:[123, 123] <br>
         * <br>
         * 
         * 生成IRecord记录
         * @param recsStream IRecord记录
         * @param initrec 初始化 record
         * @return 层级结构的IRecord
         */
        static IRecord REC3(final Stream<IRecord> recsStream, final IRecord initrec) {
            return REC3(recsStream,initrec,null);
        }
        
        /**
         * 把一个扁平结构的 recs 转换成一个层级结构的IRecord <br>
         * 示例:<br>
         * var rec = REC("a/b/c",123,"a/b/d",456,"e/f",7,"g",8); <br>
         * REC3(rec,REC()).dfs_forone((p,v)->{ <br>
         *  System.out.println(p+"--->"+v); <br>
         * });<br>
         * 结构如下:<br>
         * /g--->8 <br>
         * /a/b/c--->123 <br>
         * /a/b/d--->456 <br>
         * /e/f--->7 <br>
         * 
         * <br>
         * 注意:<br>
         * 不同Record 之间的同名键名 会彼此覆盖:比如 REC3(REC("a",123,"a/b/c",234)). <br>
         * REC3(REC("a",123,"a/b/c",234)).dfs_forone((p, v) -> { <br>
         *   System.out.println(p + "--->" + v); <br>
         * }); <br>
         * 会只生成 /a/b/c--->234 一条记录。原因是 "a"的123被"a/b/c" 给覆盖掉了。<br>
         * a/b/c 表示 a是一个复合结构，因此 原来的 单值 123,就被替换换。<br>
         * 即 一个层级节点：只能要么是 复合节点，要么是单值节点 不能二者兼具。<br>
         * 
         * <br>
         * REC3(REC("a",1),REC("a",2)) 会把 同名的key 合并在一起:值别拼接到一个数组中。即  a:[1,2]  <br>
         * 
         * 示例代码: <br>
         * final var s = S(REC("a/b/c",123,"a",98),REC("a/b/c",123,"a/x",98)); <br>
         * System.out.println(HIERACHIES(s,REC(),"/")); <br>
         * 输出:a:x:98   b:c:[123, 123] <br>
         * <br>
         * 
         * 生成IRecord记录
         * @param recsStream IRecord记录
         * @param initrec 初始化 record
         * @param pattern key的路径分解的 分隔符的模式pattern,默认(空值null)的 分隔模式pattern标识为 "[\\s,/\\.\\\\]+"
         * @return 层级结构的IRecord
         */
        static IRecord REC3(final Stream<IRecord> recsStream, final IRecord initrec, final String pattern) {
            return HIERACHIES(recsStream,initrec,pattern==null?"/":pattern);
        }
        
        /**
         * 把一个扁平结构的 recs 转换成一个层级结构的IRecord <br>
         * 示例:<br>
         * var rec = REC("a/b/c",123,"a/b/d",456,"e/f",7,"g",8); <br>
         * REC3(rec,REC()).dfs_forone((p,v)->{ <br>
         *  System.out.println(p+"--->"+v); <br>
         * });<br>
         * 结构如下:<br>
         * /g--->8 <br>
         * /a/b/c--->123 <br>
         * /a/b/d--->456 <br>
         * /e/f--->7 <br>
         * 
         * <br>
         * 注意:<br>
         * 不同Record 之间的同名键名 会彼此覆盖:比如 REC3(REC("a",123,"a/b/c",234)). <br>
         * REC3(REC("a",123,"a/b/c",234)).dfs_forone((p, v) -> { <br>
         *   System.out.println(p + "--->" + v); <br>
         * }); <br>
         * 会只生成 /a/b/c--->234 一条记录。原因是 "a"的123被"a/b/c" 给覆盖掉了。<br>
         * a/b/c 表示 a是一个复合结构，因此 原来的 单值 123,就被替换换。<br>
         * 即 一个层级节点：只能要么是 复合节点，要么是单值节点 不能二者兼具。<br>
         * 
         * <br>
         * REC3(REC("a",1),REC("a",2)) 会把 同名的key 合并在一起:值别拼接到一个数组中。即  a:[1,2]  <br>
         * 示例代码:
         * final var s = S(REC("a/b/c",123,"a",98),REC("a/b/c",123,"a/x",98)); <br>
         * System.out.println(HIERACHIES(s,REC(),"/")); <br>
         * 输出:a:x:98   b:c:[123, 123] <br>
         * 
         * 生成IRecord记录
         * @param recsStream IRecord记录
         * @param initrec 初始化 record
         * @param pattern 路径元素的分隔符
         * @return 层级结构的IRecord
         */
        static IRecord HIERACHIES(final Stream<IRecord> recsStream,
                                  final IRecord initrec, final String pattern) {
            
            final var path2recs = new HashMap<String,Stream<IRecord>>(); // 路径 -> IRecord 集合
            // 把  同名key 进行 进行分组,用于 IRecord 的compute 计算。
            final Function<KVPair<String,Object>,BiFunction<String, Object, Object>> kvp_remapper = (kvp) -> {
                return (k,v) -> {
                    if(v==null)return kvp.value();
                    @SuppressWarnings("unchecked")
                    final List<Object> vv = v instanceof List
                        ? (List<Object>) v // 把单元素的值变成列表形式的值
                        : Stream.of(v).collect(Collectors.toList()); // 转换成列表形式的值
                    vv.add(kvp.value()); // 加入新的kvp元素
                    return vv;// 返回合并之后的结果
                }; // (k,v)->{}
            };// kvp_remapper
            
            recsStream.flatMap(IRecord::stream)// 把recsStream分解成 KVPair 序列流。
            //把键key字段分解成2部分键名序列
            .map(e -> KVPair.split( e.key ( KVPair
                 // 第一部分只有一个元素的集合,第二部分为剩余的元素的集合
                .mkll(pattern)), 0) .map ( ( kk1, kk2 ) -> KVP (
                    JOIN ( kk1, "/" ), // 第一部分键名 连接成路径
                    KVP ( JOIN( kk2, "/" ), // 第二部分键名连接成路径
                         e.value() ) // 键值
                ) ) // mkll
            ).collect( Collectors.groupingBy(KVPair::key) ) // 按照第一部分键名进行分组:KVPair 进行阶层分组。
            .forEach((pathKey, pathValues) -> {// key, 键值对集合
                final var kvps = pathValues.stream()
                .map(pathValue->{
                    final var kvp = pathValue.value();
                    if(kvp.key().matches("\\s*")) {// key 单值节点
                        initrec.compute( pathKey, kvp_remapper.apply(kvp));// 和多个键值合并到一块。
                        return null; // 单值节点不予进行递归处理。
                    } else {// key 为复合节点
                        return pathValue;
                    }//if
                }).filter(Objects::nonNull) // 滤除掉 空值
                .map(e->KVP(e._2()._1(),e._2()._2()));
                
                final var rec = REC();// 新的节点
                kvps.forEach( kvp -> {// 合并同名键
                    rec.compute( kvp.key(), kvp_remapper.apply(kvp));// 和多个键值合并到一块。
                }); // forEach
                
                // 对于非空rec给予继续分解调用
                // 把具有共同的 path路径的字阶层IRecord(KVPair集合) 归拢起来,合并入path2recs
                if(!rec.isEmpty()) path2recs.merge(pathKey, Stream.of(rec), Stream::concat); // 合并具相同路径阶层路径path的IRecord归并到一处。
            });// forEach
            
            path2recs.forEach( (path,rr) -> {
                initrec.add(path,REC());// 为键名k,添加一个占位符对象，空的IRecord,通过递归进行更深层次的键值设置
                HIERACHIES(rr,(IRecord)initrec.get(path),"/");// 递归步进
            });// forEach
            
            return initrec;// 返回设置结果
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并。注意当T为Character类型的时候。返回的结构就构成了一个Trie结构。
         * @param <T> 路径键名序列
         * @param kvplStream 键值对儿 集合 流
         * @return KVPair集合进行层次合并
         */
        static <T> Map<T,Object> KVPSMERGE(final Stream<List<KVPair<List<T>, Object>>> kvplStream) {
            return KVPSMERGE(kvplStream,(T)null);
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并，注意当T为Character类型的时候。返回的结构就构成了一个Trie结构。
         * @param <T> 路径键名序列
         * @param <U> KVPair 的值类型
         * @param kvps 键值对儿  流
         * @return KVPair集合进行层次合并
         */
        static <T,U> Map<T,Object> KVPSMERGE2(final Stream<KVPair<List<T>, U>> kvps) {
            @SuppressWarnings("unchecked")
            final List<KVPair<List<T>,Object>> kvpl = (List<KVPair<List<T>,Object>>)(Object)kvps.collect(Collectors.toList());
            return KVPSMERGE2(kvpl);
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并，注意当T为Character类型的时候。返回的结构就构成了一个Trie结构。
         * @param <T> 路径键名序列
         * @param <U> KVPair 的值类型
         * @param kvpll 键值对儿 集合 列表
         * @return KVPair集合进行层次合并
         */
        static <T,U> Map<T,Object> KVPSMERGE(final List<List<KVPair<List<T>, U>>> kvpll) {
            @SuppressWarnings("unchecked")
            Stream<List<KVPair<List<T>,Object>>> stream = ((List<List<KVPair<List<T>,Object>>>)(Object)kvpll).stream();
            return KVPSMERGE(stream,(T)null);
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并，注意当T为Character类型的时候。返回的结构就构成了一个Trie结构。
         * @param <T> 路径键名序列
         * @param kvpl 键值对儿 集合 流
         * @return KVPair集合进行层次合并
         */
        static <T,U> Map<T,Object> KVPSMERGE2(final List<KVPair<List<T>, U>> kvpl) {
            @SuppressWarnings("unchecked")
            Stream<List<KVPair<List<T>,Object>>> stream = Stream.of(((List<KVPair<List<T>,Object>>)(Object)kvpl));
            return KVPSMERGE(stream,(T)null);
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并，注意当T为Character类型的时候。返回的结构就构成了一个Trie结构。
         * @param <T> 路径键名序列
         * @param kvplStream 键值对儿 集合 流
         * @param nullkey 空键值名的 默认值
         * @return KVPair集合进行层次合并
         */
        static <T> Map<T,Object> KVPSMERGE(final Stream<List<KVPair<List<T>, Object>>> kvplStream, final T nullkey) {
            final var ret = new HashMap<T,Object>();// 返回值
            
            kvplStream.flatMap(Collection::stream)
            .collect( Collectors.groupingBy( e -> e.key().size()<1 
                ? nullkey // 默认空值对应的 key
                : e.key().get(0)) ) // 根据第一层元素进行分组
            .forEach((key,kvps)->{
                kvps.stream().map( e -> // 即path2vlaue的层级结构进行 阶层分析。
                    KVP ( // 阶层结构分解 提取 子阶层
                        e.key().size() < 1 
                            ? e.key() // 空列表
                            : e.key().subList(1, e.key().size()), // 次级阶层结构的路径
                        e.value() // 次级阶层 结构的值
                    )// KVP
                ).collect(Collectors.groupingBy(e->e.key().size())) // 次级阶层结构分组
                .forEach( (length,vv) -> { // 次级阶层 结构处理
                    if( length==0 ) { // 单值元素,次级阶层长度为0
                        final var ll = vv.stream().map(Tuple2::_2).collect(Collectors.toList());
                        ret.put(key,ll.size()==1?ll.get(0):ll);
                    }else {// 次级阶层长度不为0
                        ret.put(key, KVPSMERGE(Stream.of(vv)));
                    }//if length
                });// forEach length,vv
            });// forEach key,kvps
            
            return ret;
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并
         * @param kvplStream 键值对儿 集合 流
         * @return KVPair集合进行层次合并
         */
        static Map<String,Object> RECMERGE(final Stream<IRecord> kvplStream){
            return RECMERGE(kvplStream,null);
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并
         * @param kvplStream 键值对儿 集合 流
         * @param pattern 路径分隔符号，默认(空值)为 "/",注意 pattern 需要采用正则表达式的形式 对于 $,|,^等符号需要给予进行转义。 
         * @return KVPair集合进行层次合并
         */
        static Map<String,Object> RECMERGE(final Stream<IRecord> kvplStream, final String pattern){
            final Function<IRecord,List<KVPair<List<String>,Object>>> mapper = rec-> rec.stream().map(p -> KVP(
                p.key(line->{
                    final var regex = pattern==null ? "/" :pattern; // 路径元素分隔方式。
                    return Arrays.asList(line.split(regex));
                }), // 阶层路径元素 列表
                p.value() // 阶层
            )).collect(Collectors.toList());
            return KVPSMERGE(kvplStream.map(mapper));
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并
         * @param records 键值对儿 集合 流
         * @return KVPair集合进行层次合并
         */
        static Map<String,Object> RECMERGE(final IRecord... records){
            return RECMERGE(Stream.of(records));
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并
         * @param map 待转换的键值列表
         * @return KVPair集合进行层次合并
         */
        @SuppressWarnings("unchecked")
        static IRecord MAP2REC(final Map<String, Object> map){
            final var rec = REC(map);
            map.keySet().forEach(key->rec.computeIfPresent(key, v -> v instanceof Map ? MAP2REC((Map<String,Object>)v):v));
            return rec;
        }
        
        
        /**
         * 把 一个  KVPair集合进行层次合并 REC3的另一种实现方式<br>
         * 
         * eg:<br>
         * final var rec = RECMERGE2(REC("a", 4, "a/b/c", 234), REC("a/b/d", 567), REC("a/b/d", 567)); <br>
         * 返回:<br>
         * a:b:c:234    d:[567, 567]<br>
         * 
         * @param records 键值对儿 集合 流
         * @return KVPair集合进行层次合并
         */
        static IRecord RECMERGE2(final IRecord... records){
            return MAP2REC(RECMERGE(Stream.of(records)));
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并 REC3的另一种实现方式
         * 
         * eg:<br>
         * final var rec = RECMERGE2(REC("a", 4, "a/b/c", 234), REC("a/b/d", 567), REC("a/b/d", 567)); <br>
         * 返回:<br>
         * a:b:c:234    d:[567, 567]<br>
         * 
         * 数据透视表功能演示: <br>
         * final var digits = "0123456789".split("");  <br>
         * final var ai = new AtomicInteger(0); <br>
         * Elem.cph2(asList(digits,digits,digits,digits,digits)).map(IRecord::L2REC) <br>
         * .map(path->REC(JOIN(path.ss().subList(0, 4)), ai.getAndIncrement() )) // 生成一个 path2value结构,这是一种阶层结构的方法方法 <br>
         * .collect(llclc(IRecord::RECMERGE2)) // 阶层化 Record 集合 <br>
         * .dfs_forall2(System.out::println); <br>
         * 
         * @param records 键值对儿 集合 流
         * @return KVPair集合进行层次合并
         */
        static IRecord RECMERGE2(final List<IRecord> records){
            return MAP2REC(RECMERGE(records.stream()));
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并 REC3的另一种实现方式,其实 一个 RECMERGE2 结合 llclc 可以实现 数据透视表的功能。 
         * 
         * eg:<br>
         * final var rec = RECMERGE2(REC("a", 4, "a/b/c", 234), REC("a/b/d", 567), REC("a/b/d", 567)); <br>
         * 返回:<br>
         * a:b:c:234    d:[567, 567]<br>
         * 
         * 数据透视表功能演示: <br>
         * final var digits = "0123456789".split(""); <br>
         * final var ai = new AtomicInteger(0); <br>
         * Elem.cph2(asList(digits,digits,digits,digits,digits)).map(IRecord::L2REC) <br>
         * .map(path->REC(JOIN(path.ss().subList(0, 4)), ai.getAndIncrement() )) // 生成一个 path2value结构,这是一种阶层结构的方法方法 <br>
         * .collect(llclc(IRecord::RECMERGE2)) // 阶层化 Record 集合 <br>
         * .dfs_forall2(System.out::println);<br>
         * 
         * @param records 键值对儿 集合 流
         * @param pattern 路径分隔符号，默认(空值)为 "/"
         * @return KVPair集合进行层次合并
         */
        static IRecord RECMERGE2(final List<IRecord> records, String pattern){
            return MAP2REC(RECMERGE(records.stream(),pattern));
        }
        
        /**
         * 把 一个  KVPair集合进行层次合并 REC3的另一种实现方式
         * 
         * eg:<br>
         * final var rec = RECMERGE2(REC("a", 4, "a/b/c", 234), REC("a/b/d", 567), REC("a/b/d", 567)); <br>
         * 返回:<br>
         * a:b:c:234    d:[567, 567]<br>
         * 
         * @param records 键值对儿 集合 流
         * @return KVPair集合进行层次合并
         */
        static IRecord RECMERGE2(final Stream<IRecord> records){
            return MAP2REC(RECMERGE(records));
        }
        
        /**
         * 把一个数组元素转换成一个IRecord对象 键值对序列为[key_i,tt[i]]
         * 
         * @param tt    数组元素对象
         * @param t2key 元素转换成key,把一个tt[i]->key_i,进而成为一个键值对儿[key_i,tt[i]]
         * @return IRecord对象
         */
        static <T> IRecord A2REC(final T[] tt, final Function<T, String> t2key) {
            return REC(Stream.of(tt).flatMap(e -> Stream.of(t2key.apply(e), e)).toArray());
        }

        /**
         * 把一个数组元素转换成一个IRecord对象 键值对序列为[i,tt[i]],i从0开始
         * 
         * @param <T> 数组元素类型
         * @param tt  数组元素对象
         * @return IRecord对象
         */
        static <T> IRecord A2REC(final T[] tt) {
            final var aint = new AtomicInteger(0);
            final Function<Object, String> t2key = o -> aint.getAndIncrement() + "";
            return REC(Stream.of(tt).flatMap(e -> Stream.of(t2key.apply(e), e)).toArray());
        }
        
        /**
         * A2REC 的别名
         * 把一个数组元素转换成一个IRecord对象
         * 键值对序列为[i,tt[i]],i从0开始
         * @param <T> 数组元素类型
         * @param tt 数组元素的序列
         * @return IRecord对象
         */
        @SafeVarargs
        static <T> IRecord A2R(final T... tt) {
            return A2REC(tt);
        }
        
        /**
         * A2REC 的别名: example, 用来做 制作一个 概念示例。<br>
         * 比如 EG(1,"张三","上海",198).keys("id,name,address") 就构建了一个 用户概念。<br>
         * 把一个数组元素转换成一个IRecord对象
         * 键值对序列为[i,tt[i]],i从0开始
         * @param <T> 数组元素类型
         * @param tt 数组元素的序列
         * @return IRecord对象
         */
        @SafeVarargs
        static <T> IRecord EG(final T... tt) {
            return A2REC(tt);
        }
        
        /**
         * 用一个IRecord 来表示一个点数据Point，键名为"0"
         * 把一个对象转换成Object: Pair:{0,Object}
         * @param obj 数据对象
         * @return 键名为"0" 的IRecord
         */
        static IRecord P(Object obj) {
            return REC("0",obj);// 生成默认键名为0
        }
        
        /**
         * 解析一个字符串数据，把它拆分成字符串数组
         * 然后把该数组元素转换成一个IRecord对象
         * 键值对序列为[i,tt[i]],i从0开始
         * 
         * 例如：STRING2REC("1,2,3,4","[,/\\\\]+") 生成 {0:1,1:2,2:3,3:4}
         * 
         * @param line 带解析的数据行
         * @param delim 分隔符,分隔符好的正则表达式。比如 "[,/\\\\]+" 表示  使用  “,” “/” “\” 作为分隔符号。
         * @return 解析行的line而得到的IRecord
         */
        static IRecord STRING2REC(final String line, final String delim) {
           return A2REC(line.split(delim));
        }
        
        /**
         * 解析一个字符串数据，把它拆分成字符串数组<br>
         * 然后把该数组元素转换成一个IRecord对象<br>
         * 键值对序列为[i,tt[i]],i从0开始<br>
         * 
         * 例如：STRING2REC("1,2,3,4","[,/\\\\]+") 生成 {0:1,1:2,2:3,3:4}<br>
         * 
         * 默认的delim "[,/\\\\]+"<br>
         * @param line 带解析的数据行
         * @return 解析行的line而得到的IRecord
         */
        static IRecord STRING2REC(final String line) {
           return A2REC(line.split("[,/\\\\]+"));
        }

        /**
         * 把一个数组元素转换成一个IRecord对象<br>
         * 键值对序列为[key_i,tt[i]] <br>
         * 
         * @param <T> 数组元素类型
         * @param ss 数组元素对象
         * @param s2key 元素转换成key,把一个tt[i]->key_i,进而成为一个键值对儿[key_i,tt[i]]
         * @return IRecord对象
         */
        static <T> IRecord STREAM2REC(final Stream<T> ss, final Function<T, String> s2key) {
            return REC(ss.flatMap(e->Stream.of(s2key.apply(e),e)).toArray());
        }
        
        /**
         * 把一个元素流转换成一个IRecord对象
         * 键值对序列为[i,tt[i]],i从0开始
         * 
         * @param <T> 数组元素类型
         * @param ss 数组元素对象
         * @return IRecord对象
         */
        static <T> IRecord STREAM2REC(final Stream<T> ss) {
            final var aint = new AtomicInteger(0);
            final Function<Object,String> t2key=o->aint.getAndIncrement()+"";
            return REC(ss.flatMap(e->Stream.of(t2key.apply(e),e)).toArray());
        }
        
        /**
         * 把一个列表转换成一个IRecord对象
         * 键值对序列为[key_i,tt[i]]
         * 
         * @param <T> 数组元素类型
         * @param ll 列表元素对象
         * @param t2key 元素转换成key,把一个tt[i]->key_i,进而成为一个键值对儿[key_i,tt[i]]
         * @return IRecord对象
         */
        static <T> IRecord L2REC(final List<T> ll, final Function<T, String> t2key) {
            return REC(ll.stream().flatMap(e->Stream.of(t2key.apply(e),e)).toArray());
        }
        
        /**
         * 把一个列表转换成一个IRecord对象,
         * 键值对序列为[i,tt[i]],i从0开始
         * @param <T> 数组元素类型
         * @param ll 数组元素对象:
         * @return IRecord对象
         */
        static <T> IRecord L2REC(final List<T> ll) {
            final var aint = new AtomicInteger(0);
            final Function<Object,String> t2key=o->aint.getAndIncrement()+"";
            return REC(ll.stream().flatMap(e->Stream.of(t2key.apply(e),e)).toArray());
        }
        
        /**
         * 把一个KVS列表转换成一个IRecord对象,
         * 
         * @param kvs 键值列表
         * @return IRecord对象
         */
        static <T> IRecord KVS2REC(final List<? extends KVPair<String, T>> kvs) {
            return KVS2REC(kvs.stream());
        }

        /**
         * 把一个KVS列表转换成一个IRecord对象,
         * 
         * @param kvsStream 键值列表的流
         * @return IRecord对象
         */
        static <T> IRecord KVS2REC(final Stream<? extends KVPair<String, T>> kvsStream) {
            final IRecord rec = REC();
            if (kvsStream != null)
                kvsStream.forEach(kvp -> rec.add(kvp.key(), kvp.value()));
            return rec;
        }
        
        /**
         * 行形式转换成列形式。即每一元素为列向量的IRecord
         * @param recs 行形式的Record集合
         * @param keys 字段键名 如果为null, 采用recs 的一个元素的键名集合。 
         * @return IRecord 即每一元素为列向量的IRecord
         */
        static IRecord ROWS2COLS(final List<IRecord> recs, final List<String> keys){
            if(recs==null || recs.size()<1 ) return REC();
            final var first = recs.stream().filter(Objects::nonNull).findFirst().orElse(null);
            if(first==null)return REC();
            final var kk = (keys==null||keys.size()<1 ?first.keys() :keys)
                .toArray(String[]::new);
            final var mm = new LinkedHashMap<String,List<Object>>();
            recs.forEach(line->{
                for(var k: kk){
                    mm.compute(k, (_k,v)->{
                        if(v==null)v = new LinkedList<>();
                        v.add(line.get(_k));
                        return v;
                    });
                };// for
            });
            
            return REC(mm);
        }
        
        /**
         * 行形式转换成列形式。即每一元素为列向量的IRecord
         * @param recs 行形式的Record流
         * @return IRecord 即每一元素为列向量的IRecord
         */
        static IRecord ROWS2COLS(List<IRecord> recs){
          return ROWS2COLS(recs,null);
        }
        
        /**
         * 行形式转换成列形式。即每一元素为列向量的IRecord
         * @param recs 行形式的Record集合
         * @param keys 字段键名 如果为null, 采用recs 的一个元素的键名集合。 
         * @return IRecord 即每一元素为列向量的IRecord
         */
        static IRecord ROWS2COLS(final Stream<IRecord> recs, final List<String> keys) {
            return ROWS2COLS(recs.collect(Collectors.toList()),null);
        }
        
        /**
         * 行形式转换成列形式。即每一元素为列向量的IRecord
         * 
         * @param recs 行形式的Record流
         * @return IRecord 即每一元素为列向量的IRecord
         */
        static IRecord ROWS2COLS(Stream<IRecord> recs) {
            return ROWS2COLS(recs, null);
        }

        /**
         * ROWS CoLleCt 行归集器 函数<br>
         * 把IRecord视为一个DataFrame dfm,而后 把dfm转换成个一个行流，最后使用 collector进行归集。
         * 
         * @param <R>       结果类型
         * @param collector 行归集器
         * @return 一个 rec->R 的函数
         */
        static <R> Function<IRecord, R> ROWSCLC(final Collector<IRecord, List<IRecord>, R> collector) {
            return rec -> rec.rows2().collect(collector);
        }

        /**
         * ROWS2COLS 的别名 行形式转换成列形式。即每一元素为列向量的IRecord
         * 
         * @param recs 行形式的Record集合
         * @return IRecord 即每一元素为列向量的IRecord
         */
        static IRecord R2C(List<IRecord> recs) {
            return ROWS2COLS(recs, null);
        }

        /**
         * 标准版的记录生成器, map 生成的是LinkedRecord
         * 
         * @param values:key1,value1,key2,value2,....
         * @return IRecord对象
         */
        static IRecord R(final Object... values) {
            return REC(values);
        }
        
        /**
         * 制作一个列表
         * @param <T> tt 的元素类型
         * @param tt 列表元素
         * @return List<T>
         */
        @SafeVarargs
        static <T> List<T> L(final T... tt) {
            return Arrays.asList(tt);
        }
        
        /**
         * 制作一个流
         * @param <T> tt 的元素类型
         * @param tt 列表元素
         * @return Stream<T>
         */
        @SafeVarargs
        static <T> Stream<T> S(final T... tt) {
            return Stream.of(tt);
        }
        
        /**
         * 制作一个数组
         * @param <T> tt的元素类型
         * @param tt 列表元素：当TT中的元素异质接类型的时候，比如A(1,1d,1l) T被视作Object类型。
         * @return T类型数组
         */
        @SuppressWarnings("unchecked")
        static <T> T[] A(final T... tt) {
            final var classes = Stream.of(tt).collect(Collectors.groupingBy(e->e==null?Object.class:e.getClass())).keySet();// 提取所有类别
            final Function<Collection<Class<?>>,Class<?>> num_predicate = cc->{
                if(cc.size()>1) {
                    var b = cc.stream().allMatch(Number.class::isAssignableFrom);// 判断是否是数值类型
                    if(b)return Number.class;// 数值类型
                    b = cc.stream().allMatch(Serializable.class::isAssignableFrom);// 判断是否是数值类型
                    if(b) return Serializable.class;// 其他类型采用Serializable
                    return Object.class;
                }else if(cc.size()==1){
                    return cc.iterator().next();
                }//if
                
                return Object.class;
            };// num_predicate
            
            final var componentType = classes.size() == 1 
                ? (Class<T>)(Object)classes.iterator().next()
                : (Class<T>)(Object)num_predicate.apply(classes);
            return Arrays.asList(tt).toArray(n->(T[])Array.newInstance(componentType, n));
        }
        
        /**
         * 制作一个数组:在 tt 前面插入一个元素t
         * @param <T> tt的元素类型
         * @param t 列表元素
         * @param tt 列表元素
         * @return T[]
         */
        static <T> T[] A(T t, T[] tt) {
           return CONS(t,tt);
        }
        
        /**
         * 制作一个数组:在tt 后面插入一个元素t
         * @param <T> tt的元素类型
         * @param tt 列表元素
         * @param t 列表元素
         * @return T[]
         */
        @SuppressWarnings("unchecked")
        static <T> T[] A(T[] tt, T t) {
            final var dd = new LinkedList<T>();
            dd.add(t);
            dd.addAll(Arrays.asList(tt));
            Class<T> componentType = dd.stream().filter(Objects::nonNull).map(e->(Class<T>)e.getClass()).findAny().orElse((Class<T>)Object.class);
            return dd.toArray(n->(T[])Array.newInstance(componentType, n));
        }
        
        /**
         * 制作一个数组:在 tt 前面插入一个元素t
         * @param <T> tt1,tt2 的 元素类型
         * @param tt1 列表元素数组1
         * @param tt2 列表元素数组2
         * @return T[]
         */
        @SuppressWarnings("unchecked")
        static <T> T[] A(T[] tt1, T[] tt2) {
            final var dd = new LinkedList<T>();
            if(tt1!=null)dd.addAll(Arrays.asList(tt1));
            if(tt2!=null)dd.addAll(Arrays.asList(tt2));
            Class<T> componentType = dd.stream().filter(Objects::nonNull).map(e->(Class<T>)e.getClass()).findAny().orElse((Class<T>)Object.class);
            return dd.toArray(n->(T[])Array.newInstance(componentType, n));
        }
        
        /**
         * FixedArray
         * 制作一个数组:定长数组:size 为数组长度,数组不足采用zeros进行补充,多余数据给予删除
         * @param <T> 元素类型
         * @param tt 列表元素数组
         * @param zeros 空值序列:会会采用循环补填的方式进行数据填充。
         * @param size 数组长度
         * @return T[]
         */
        @SuppressWarnings("unchecked")
        static <T> T[] FA(final T[] tt, final T[] zeros, final int size) {
            final var dd = new LinkedList<T>();
            if(tt!=null)dd.addAll(Arrays.asList(tt));
            if(dd.size()>size) {
                while(dd.size()>size) dd.removeLast(); // 去除掉尾部的多余数据
            }else if(dd.size()<size){
                // 使用zeros 进行数据补填
                for(int i=tt==null?0:tt.length;i<size;i++) dd.add(zeros==null?null:zeros[i%zeros.length]);
            }//if
            
            final Class<T> componentType = dd.stream().filter(Objects::nonNull)
                .map(e->(Class<T>)e.getClass()).findAny().orElse((Class<T>)Object.class);
            
            return dd.toArray(n->(T[])Array.newInstance(componentType, n));
        }
        
        /**
         * FixedArray
         * 制作一个数组:定长数组:size 为数组长度,数组不足采用zeros进行补充,多余数据给予删除
         * @param <T> 元素类型
         * @param tt 列表元素数组
         * @param zeros 空值序列:会会采用循环补填的方式进行数据填充。
         * @param size 数组长度
         * @return T[]
         */
        @SuppressWarnings("unchecked")
        static <T> T[] FA(final T[] tt, final T zeros, final int size) {
            return FA(tt,A(zeros),size);
        }
        
        /**
         * 提取数组的第一个元素,术语来自于 LISP
         * 
         * @param <T> 数组元素的类型
         * @param tt 数组
         * @return T 数组元素
         */
        static <T> T CAR(final T[] tt) {
            return (tt==null||tt.length<1)? null:tt[0];
        }
        
        /**
         * 提取数组除了第一个元素之外的其他元素,术语来自于 LISP
         * 
         * @param <T> 数组元素的类型
         * @param tt 数组元素
         * @return T[] 子数组
         */
        @SuppressWarnings("unchecked")
        static <T> T[] CDR(final T[] tt) {
            if(tt.length<2)return null;
            var ll = Arrays.asList(tt);
            var tclazz = ll.stream().filter(Objects::nonNull).map(e->(Class<T>)e.getClass()).findAny().orElse(null);
            if(tclazz==null)return null;
            return ll.subList(1, tt.length).toArray(n->(T[])Array.newInstance(tclazz,n));
        }

        /**
         * 制作一个数组:在 tt 前面插入一个元素t,术语来源于 lisp
         * @param <T> 数组元素类型
         * @param t 列表元素
         * @param tt 元素列表
         * @return T[]
         */
        @SuppressWarnings("unchecked")
        static <T> T[] CONS(T t, T[] tt) {
            
            if(t!=null && tt==null) {
                T[] aa = (T[])Array.newInstance(t.getClass(), 1);
                aa[0] = t;
                return aa;
            }else {
                if(tt==null && t==null) {
                    return null;
                }else {
                    if(tt==null||tt.length<1)return Collections.singletonList(t).toArray(n->(T[])Array.newInstance(t.getClass(), n));// 生成一个单元素数组
                    final var dd = Stream.of(Stream.of(t),Arrays.stream(tt)).flatMap(e->e).collect(Collectors.toList());
                    Class<T> componentType = dd.stream().filter(Objects::nonNull).map(e->(Class<T>)e.getClass()).findAny().orElse((Class<T>)Object.class);
                    return dd.toArray(n->(T[])Array.newInstance(componentType, n));
                }
            }// if
        }
        
        /**
         * 数组进行倒转。
         * @param <T> 数据元素类型
         * @param tt 列表元素
         * @return T[]
         */
        static<T> T[] REV(T[] tt){
            if(tt==null)return null;
            return LittleTree.reverse(tt);
        }

        /**
         * 制作一个Map<String,Object>
         * @param tt 列表元素
         * @return Map<String,Object>
         */
        static Map<String,Object> M(final Object... tt) {
            return _REC(tt).toMap();
        }

        /**
         * 等价函数
         */
        @SuppressWarnings("unchecked")
        static <T> Function<Object,T> identity(final Class<T> tcls){
            return (Object o)->(T)o;
        }
        
        /**
         * 把一个 IRecord节点 转换成 一个 树形结构  Node &lt String &gt;
         * @param rec IRecord 对象
         * @param rootName 根节点名称 , 默认值(null) 为 "root"
         * @param valuekey IRecord KVPair的 value 值在 Node 的props 中的键值名,默认值 为 "value"
         * @return Node &lt String &gt;
         */
        static Node<String> TREENODE(final IRecord rec, final String rootName, final String valuekey){
            
            final var finalvk  =  valuekey == null?"value":valuekey;
            final var finalrn  =  rootName == null?"root":rootName;
            
            // BiConsumer
            final class BCS implements BiConsumer<String, Object> {
                
                // 构造函数
                public BCS(Node<String> parent) {
                    this.parent2value = KVP(parent, null);
                }
                
                @Override 
                public void accept(final String name, final Object value) {
                    final var node = new Node<>(name);// 创建当前节点
                    this.parent2value.key().addChild(node);
                    this.parent2value.value(value);
                    
                    if (value instanceof IRecord) ((IRecord) value).foreach(new BCS(node)); // 节点关系处理
                    else node.prop(finalvk, value);
                }
                
                private final KVPair<Node<String>, Object> parent2value;// 上级节点 与 当前节点
            } // BCS
            
            final var root = new Node<>(finalrn);
            rec.foreach(new BCS(root));
            
            return root;
        }
        
        /**
         * 行化操作：数据分析类 需要与DataMatrix 相结合生成 data.frame类型的 转换函数
         * 
         * rr:Collection<IRecord> recs 记录集合
         * row:Map 行记录
         * S:结果类型为Stream
         * 主要用途就是 完成 IRecord 向 DataMatrix的转换，但是为了保证DataMatrix 与IRecord 的独立。而设置这个函数。比如
         * var dm = new DataMatrix<> (rr2rowS(recs),Integer.class); 就构造了一个 DataMatrix 对象。
         * 
         * @param recs record 集合
         * @return 生成一个hashmap 的集合
         */
        
        static <T> Stream<LinkedHashMap<String,T>> rr2rowS(final Collection<IRecord> recs) {
           return rr2rowS(recs.stream());
        }

        /**
         * 行化操作：数据分析类 需要与DataMatrix 相结合生成 data.frame类型的 转换函数
         * 
         * rr:Collection<IRecord> recs 记录集合
         * row:Map 行记录
         * S:结果类型为Stream
         * 主要用途就是 完成 IRecord 向 DataMatrix的转换，但是为了保证DataMatrix 与IRecord 的独立。而设置这个函数。比如
         * var dm = new DataMatrix<> (rr2rowS(recs),Integer.class); 就构造了一个 DataMatrix 对象。
         * 
         * @param stream records 的集合
         * @return 生成一个hashmap 的集合
         */
        @SuppressWarnings("unchecked")
        static <T> Stream<LinkedHashMap<String,T>> rr2rowS(final Stream<IRecord> stream) {
            return (Stream<LinkedHashMap<String,T>>)(Object) stream.map(IRecord::toLhm);
        }

        /**
         * 行化操作：数据分析类 需要与DataMatrix 相结合生成 data.frame类型的 转换函数
         * r:record 单条记录
         * row:Map 行记录
         * s:结果类型为Stream 
         * 主要用途就是 完成 IRecord 向 DataMatrix的转换，但是为了保证DataMatrix 与IRecord 的独立。而设置这个函数。比如
         * var dm = new DataMatrix<> (rr2rowS(recs),Integer.class); 就构造了一个 DataMatrix 对象。
         * 
         * @param rec 的单元素：但也把他视为只有一个元素的集合。
         * @return 生成一个hashmap 的集合
         */
        @SuppressWarnings("unchecked")
        static Stream<Map<String, ?>> r2rowS(final IRecord rec) {
            return (Stream<Map<String, ?>>) (Object) Stream.of(rec.toEscapedMap());
        }
        
        /**
         * 一般用法就是对于一个 Records List,通过某种某种classifier:根分组成一个map 这是一个 List 转Map的方法。
         * 需要注意 classifier 需要保证不会把由多个元素给到相同组。所以classifier 一般就是Records 记录的候选主键：比如,id,name 之类
         * 可以唯一标识 record的字段属性。 
         * 
         * 比如:
         * final var rr = jdbc.sql2records(sql);
         * final var map = rr.stream().collect(Collectors.groupingBy(e->e.str("name"),// name 唯一标识e 
         *    atomic_collector(e->e.get("cnt"))));// rr->map
         * 
         * 但值容器：即只保存一个值。
         * 把一个T类型的元素给归约成一个U类型的单个元素。
         * @param t2u 把T类型转换成U类型的变换杉树
         * @param <T> Stream 元素类型
         * @param <U> t2u 生成的Value值
         * @return U类型的目标值。
         */
        static <T,U> Collector<T, AtomicReference<U>, U> atomic_collector(final Function<T, U> t2u){
            return Collector.of(AtomicReference::new,
                (atomic,t)->atomic.set(t2u.apply(t)),// 规约容器之
                (atomic_a,atomic_b)->atomic_b,// 合并容器之
                    AtomicReference::get);// 提取容器值
        }
        
        /**
         * 用法示例：
         * 
         * final var rr = jdbc.sql2records(sql); <br>
         * final var map = rr.stream().collect(groupby(e->e.str("name"),e->e.get("cnt"))); <br>
         * 
         * 制作一个分组器 把一个 Stream<U> 给份组成也成一个Map<K,U>
         * @param classifier T 类型的分类器，classifier 会申城一个键类型。
         * @param t2u 把T类型给转换成U类型
         * 
         * @param <T> Stream 元素类型
         * @param <K> classifier 生的K的类型
         * @param <U> t2u 生成的Value值。
         * 
         * @return Map<K,U>
         */
        static <T,K,U> Collector<T,?, Map<K,U>> groupby(final Function<T, K> classifier, final Function<T, U> t2u){
            return Collectors.groupingBy(classifier,atomic_collector(t2u));
        }
        
        /**
         * 对Stream<T> 中的元素进行 classifier 分组。
         * @param classifier 分组函数
         * 
         * @param <T> Stream 元素类型
         * @param <K> classifier 生的K的类型
         * 
         * @return Map<K,List<K>
         */
        static <T,K> Collector<T, ?, Map<K, List<T>>> groupby(final Function<T, K> classifier){
            return Collectors.groupingBy(classifier);
        }
        
        /**
         * 使用示例
         * var s = ll.stream().map(e->e.toString()).collect(join("\n"));
         * 把String <String> 通过 delimiter 连接骑起来
         * @param delimiter 分隔符
         * @return 用delimiter 分割的Stream<String>
         */
        static Collector<CharSequence, ?, String> join(final CharSequence delimiter){
            return Collectors.joining(delimiter);
        }
        
        /**
         * 对 rr 按照key的值进行分类：即key 就是分类依据。
         * @param rr 一个records 列表
         * @param key 列名：分类依据
         * @return 对rr进行分类的映射:Map<String,List<IRecord>
         */
        static Map<String,List<IRecord>> classify(final List<IRecord> rr, final String key) {
            var mm = rr.parallelStream().filter(Objects::nonNull).collect(
                groupby(e->{ var k = e.str(key); return k==null?"unknown ":k; }));
            return mm;
        }
        
        /**
           * 生成一个 数据透视表:参照Excel的实现。<br>
         * 简单说说就是把 一个列表 rr：<br>
         * a    b   c   d <br>
         * ..   ..  ..  ..<br>
         * ..   ..  ..  ..<br>
         * 分类成成 a/b/c [(a,b,c,d)],即如下图所示的 分组的层次结构，可以所所谓透视就是对一个列表 rr进行分组再分组的过程，亦即 递归分组。<br>
         * a0 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d0],[a0 b0 c0 d1],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d2],[a0 b0 c0 d3],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d4],[a0 b0 c0 d5],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d6],[a0 b0 c0 d7'],...] <br>
         * a1 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a1 b0 c0 d7],[a1 b0 c0 d9],...] <br>
         * - - c1 <br>
         * - - - [[a1 b0 c1 d10],[a1 b0 c1 d11],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a1 b1 c0 d12],[a1 b1 c0 d12],...] <br>
         * - - c1 <br>
         * - - - [[a1 b1 c1 d14],[a1 b1 c1 d15],...] <br>
         * <br>
         * 这样的层级结构。然后再对每个分组计算：调用函数 evaluator 结算集合的指标结果 U<br>
         * <br>
         * 例如:rr 需要包含：sale_name,goods_name 的key,以及 number 的值字段。<br>
         * var result = IRecord.pivotTable( rr, <br>
         *  "sale_name,goods_name".split(","), <br>
         *  ee->ee.stream().collect(Collectors.summarizingDouble(e->e.dbl("number"))).getSum() <br>
         * ); <br>
         * 
         * @param <U> 分类结果的计算器 结果类型
         * @param rr 待分类的数据集合。即源数据,null 或者长度为0返回一个空IRecord
         * @param keys 分类的key列表：分类依据字段列表。或者说 分类层级的序列
         * @param level 当前的处理节点的层级，从0开始。
         * @param parent 分类的结果的保存位置
         * @param evaluator 列指标：分类结果的计算器
         * @return 一个包含由层级关系 IRecord. 中间节点是IRecord类型，叶子节点是 U 类型。
         */
        static<U> IRecord pivotTable(final List<IRecord> rr, final String keys[], final int level,
                                     final IRecord parent, final Function<List<IRecord>, U> evaluator) {
            
            if(rr==null||rr.size()<1)return REC();// 
            final var final_keys  = (keys==null||keys.length<1)//  分类层级的序列无效,默认为全部分类
                ? rr.get(0).keys().toArray(String[]::new) // 提取第一个元素的键值作为层级分类依据。
                : keys;// 分类层级依据
            final var key = final_keys[level];// 进行分类的 分析依据字段名。
            if(level<final_keys.length) {
                // 创建新节点
                classify(rr,key).forEach((k,sub_rr)->{// 把rr 进行分类：分类型若个子分类
                    if( level!=keys.length-1 ) {// 只要不是最后一个分类项就需要继续分类。
                        final var node = REC(); parent.add(k,node);// 生成一个中间分类节点。注意不记录分组数据。
                        pivotTable(sub_rr, final_keys,level+1,node,evaluator);// 对分类节点继续分类。
                    } else {// 到达了分类层级的末端 ,即当前是最后一个分类的 key
                        parent.add(k,evaluator.apply(sub_rr));// 最后一层记录分组数据
                    }//if level
                });// classify 对 rr 按照key 的值进行分类：即key 就是分类依据。
            }// 阶层有效。
            
            return parent;// 返回计算计算
        }
        
        /**
         * 生成一个 数据透视表:参照Excel的实现。<br>
         * 简单说说就是把 一个列表 rr：<br>
         * a    b   c   d <br>
         * ..   ..  ..  ..<br>
         * ..   ..  ..  ..<br>
         * 分类成成 a/b/c [(a,b,c,d)],即如下图所示的 分组的层次结构，可以所所谓透视就是对一个列表 rr进行分组再分组的过程，亦即 递归分组。<br>
         * a0 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d0],[a0 b0 c0 d1],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d2],[a0 b0 c0 d3],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d4],[a0 b0 c0 d5],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d6],[a0 b0 c0 d7'],...] <br>
         * a1 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a1 b0 c0 d7],[a1 b0 c0 d9],...] <br>
         * - - c1 <br>
         * - - - [[a1 b0 c1 d10],[a1 b0 c1 d11],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a1 b1 c0 d12],[a1 b1 c0 d12],...] <br>
         * - - c1 <br>
         * - - - [[a1 b1 c1 d14],[a1 b1 c1 d15],...] <br>
         * <br>
         * 这样的层级结构。然后再对每个分组计算：调用函数 evaluator 结算集合的指标结果 U<br>
         * <br>
         * 例如:rr 需要包含：sale_name,goods_name 的key,以及 number 的值字段。<br>
         * var result = IRecord.pivotTable( rr, <br>
         *  "sale_name,goods_name".split(","), <br>
         *  ee->ee.stream().collect(Collectors.summarizingDouble(e->e.dbl("number"))).getSum() <br>
         * ); <br>
         * 
         * @param <U> 分类结果的计算器 结果类型
         * @param rr 待分类的数据集合。即源数据
         * @param keys 分类的key列表，分类依据字段列表。或者说 分类层级的序列
         * @param evaluator 列指标：分类结果的计算器
         * @return 一个包含由层级关系 IRecord. 中间节点是IRecord类型，叶子节点是 U 类型。
         */
        static <U> IRecord pivotTable(final List<IRecord> rr, final String keys[],
                                      final Function<List<IRecord>, U> evaluator) {
            
            return pivotTable(rr,keys,0,REC(),evaluator);
        }
        
        /**
         * 生成一个 数据透视表:参照Excel的实现。<br>
         * 简单说说就是把 一个 记录集合的列表 rr：<br>
         * a    b   c   d <br>
         * ..   ..  ..  ..<br>
         * ..   ..  ..  ..<br>
         * 分类成成 a/b/c [(a,b,c,d)],即如下图所示的 分组的层次结构，可以所所谓透视就是对一个列表 rr进行分组再分组的过程，亦即 递归分组。<br>
         * a0 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d0],[a0 b0 c0 d1],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d2],[a0 b0 c0 d3],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d4],[a0 b0 c0 d5],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d6],[a0 b0 c0 d7'],...] <br>
         * a1 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a1 b0 c0 d7],[a1 b0 c0 d9],...] <br>
         * - - c1 <br>
         * - - - [[a1 b0 c1 d10],[a1 b0 c1 d11],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a1 b1 c0 d12],[a1 b1 c0 d12],...] <br>
         * - - c1 <br>
         * - - - [[a1 b1 c1 d14],[a1 b1 c1 d15],...] <br>
         * <br>
         * 这样的层级结构。然后再对每个分组计算：调用函数 evaluator 结算集合的指标结果 U<br>
         * <br>
         * 例如:rr 需要包含：sale_name,goods_name 的key,以及 number 的值字段。<br>
         * var result = IRecord.pivotTable( rr, <br>
         *  "sale_name,goods_name".split(","), <br>
         *  ee->ee.stream().collect(Collectors.summarizingDouble(e->e.dbl("number"))).getSum() <br>
         * ); <br>
         * 
         * @param <U> 分类结果的计算器 结果类型
         * @param rr 待分类的数据集合。即源数据
         * @param keys 分类的key列表，分类依据字段列表。或者说 分类层级的序列
         * @param evaluator 列指标：分类结果的计算器
         * @return 一个包含由层级关系 IRecord. 中间节点是IRecord类型，叶子节点是 U 类型。
         */
        static <U> IRecord pivotTable2(final List<IRecord> rr, final String keys[],
                                       final Function<Stream<IRecord>, U> evaluator) {
            return pivotTable(rr,keys,0,REC(),ee->evaluator.apply(ee.stream()));
        }
            
        /**
         * 生成一个 数据透视表:参照Excel的实现。<br>
         * 简单说说就是把 一个 记录集合的列表 rr：<br>
         * a    b   c   d <br>
         * ..   ..  ..  ..<br>
         * ..   ..  ..  ..<br>
         * 分类成成 a/b/c [(a,b,c,d)],即如下图所示的 分组的层次结构，可以所所谓透视就是对一个列表 rr进行分组再分组的过程，亦即 递归分组。<br>
         * a0 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d0],[a0 b0 c0 d1],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d2],[a0 b0 c0 d3],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d4],[a0 b0 c0 d5],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d6],[a0 b0 c0 d7'],...] <br>
         * a1 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a1 b0 c0 d7],[a1 b0 c0 d9],...] <br>
         * - - c1 <br>
         * - - - [[a1 b0 c1 d10],[a1 b0 c1 d11],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a1 b1 c0 d12],[a1 b1 c0 d12],...] <br>
         * - - c1 <br>
         * - - - [[a1 b1 c1 d14],[a1 b1 c1 d15],...] <br>
         * <br>
         * 这样的层级结构。然后再对每个分组计算：调用函数 evaluator 结算集合的指标结果 U<br>
         * <br>
         * 例如:rr 需要包含：sale_name,goods_name 的key,以及 number 的值字段。<br>
         * var result = IRecord.pivotTable( rr, <br>
         *  "sale_name,goods_name".split(","), <br>
         *  ee->ee.stream().collect(Collectors.summarizingDouble(e->e.dbl("number"))).getSum() <br>
         * ); <br>
         * 
         * @param <U> 分类结果的计算器 结果类型
         * @param rr 待分类的数据集合。即源数据
         * @param keys 分类的key列表，分类依据字段列表。或者说 分类层级的序列
         * @param delim 分隔符
         * @param evaluator 列指标：分类结果的计算器
         * @return 一个包含由层级关系 IRecord. 中间节点是IRecord类型，叶子节点是 U 类型。
         */
        static <U> IRecord pivotTable(final List<IRecord> rr, final String keys, String delim,
                                      final Function<Stream<IRecord>, U> evaluator) {
            return pivotTable(rr,keys.split(delim),0,REC(),ee->evaluator.apply(ee.stream()));
        }
            
        /**
         * 生成一个 数据透视表:参照Excel的实现。<br>
         * 简单说说就是把 一个列表 rr：<br>
         * a    b   c   d <br>
         * ..   ..  ..  ..<br>
         * ..   ..  ..  ..<br>
         * 分类成成 a/b/c [(a,b,c,d)],即如下图所示的 分组的层次结构，可以所所谓透视就是对一个列表 rr进行分组再分组的过程，亦即 递归分组。<br>
         * a0 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d0],[a0 b0 c0 d1],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d2],[a0 b0 c0 d3],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d4],[a0 b0 c0 d5],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d6],[a0 b0 c0 d7'],...] <br>
         * a1 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a1 b0 c0 d7],[a1 b0 c0 d9],...] <br>
         * - - c1 <br>
         * - - - [[a1 b0 c1 d10],[a1 b0 c1 d11],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a1 b1 c0 d12],[a1 b1 c0 d12],...] <br>
         * - - c1 <br>
         * - - - [[a1 b1 c1 d14],[a1 b1 c1 d15],...] <br>
         * <br>
         * 这样的层级结构。然后再对每个分组计算：调用函数 evaluator 结算集合的指标结果 U<br>
         * <br>
         * 例如:rr 需要包含：sale_name,goods_name 的key,以及 number 的值字段。<br>
         * var result = IRecord.pivotTable( rr, <br>
         *  "sale_name,goods_name".split(","), <br>
         *  ee->ee.stream().collect(Collectors.summarizingDouble(e->e.dbl("number"))).getSum() <br>
         * ); <br>
         * 
         * @param <U> 分类结果的计算器 结果类型
         * @param rr 待分类的数据集合。即源数据
         * @param keys 分类的key列表，分类依据字段列表。或者说 分类层级的序列
         * @param evaluator 列指标：分类结果的计算器
         * @return 一个包含由层级关系 IRecord. 中间节点是IRecord类型，叶子节点是 U 类型。
         */
        static <U> IRecord pivotTable(final List<IRecord> rr, final String keys,
                                      final Function<Stream<IRecord>, U> evaluator) {
            return pivotTable(rr,keys.split(","),0,REC(),ee->evaluator.apply(ee.stream()));
        }
        
        /**
         * 生成一个 数据透视表:参照Excel的实现。<br>
         * 简单说说就是把 一个列表 rr:<br>
         * a    b   c   d <br>
         * ..   ..  ..  ..<br>
         * ..   ..  ..  ..<br>
         * 分类成成 a/b/c [(a,b,c,d)],即如下图所示的 分组的层次结构，并调用函数 evaluator 计算终端数据集合：<br>
         *  [[a0 b0 c0 di],[a0 b0 c0 dj],...]的指标结果 U <br>
         *  
         * 可以所所谓透视就是对一个列表 rr进行分组再分组的过程，亦即 递归分组。<br>
         * a0 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d0],[a0 b0 c0 d1],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d2],[a0 b0 c0 d3],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a0 b0 c0 d4],[a0 b0 c0 d5],...] <br>
         * - - c1 <br>
         * - - - [[a0 b0 c0 d6],[a0 b0 c0 d7'],...] <br>
         * a1 <br>
         * - b0 <br>
         * - - c0 <br>
         * - - - [[a1 b0 c0 d7],[a1 b0 c0 d9],...] <br>
         * - - c1 <br>
         * - - - [[a1 b0 c1 d10],[a1 b0 c1 d11],...] <br>
         * - b1 <br>
         * - - c0 <br>
         * - - - [[a1 b1 c0 d12],[a1 b1 c0 d12],...] <br>
         * - - c1 <br>
         * - - - [[a1 b1 c1 d14],[a1 b1 c1 d15],...] <br>
         * 
         * 这样的层级结构。然后再对每个分组计算：调用函数 evaluator 结算集合的指标结果 U<br>
         * 
         * 例如:rr 需要包含：sale_name,goods_name 的key,以及 number 的值字段。<br>
         * var result = IRecord.pivotTable( rr, <br>
         *  "sale_name,goods_name".split(","), <br>
         *  ee->ee.stream().collect(Collectors.summarizingDouble(e->e.dbl("number"))).getSum() <br>
         * ); <br>
         * 
         * @param <U> 分类结果的计算器 结果类型
         * @param stream 待分类的数据集合流的形式。即源数据
         * @param keys 分类的key的数组，分类依据字段列表。或者说 分类层级的序列
         * @param evaluator 列指标：分类结果的计算器
         * @return 一个包含由层级关系 IRecord. 中间节点是IRecord类型，叶子节点是 U 类型。
         */
        static <U> IRecord pivotTable(final Stream<IRecord> stream, final String keys[],
                                      final Function<List<IRecord>, U> evaluator) {
            return pivotTable(stream.collect(Collectors.toList()),keys,0,REC(),evaluator);
        }
        
        /**
         * Pivot Table 的搜集器：使用示例
         * cph(RPTS(3,L("A","B"))).stream().collect(pvtclc("0,1"));
         * @param keys 键名序列,用逗号分隔
         * @return pivotTable 的 搜集器
         */
        static Collector<IRecord,List<IRecord>,IRecord> pvtclc(final String keys){
            return Collector.of(LinkedList::new,List::add,(a,b)->{a.addAll(b);return a;}
            ,aa->IRecord.pivotTable(aa,keys,LittleTree::LIST));
        }
        
        /**
         * Pivot Table 的搜集器：搜集并变换 <br>
         * 根据 keys 做数据 透视，并把中间结果List&lt;IRecord&gt;类型, <br>
         * 存入IRecord(以keys为路径维度标记)，最后 使用 mapper 对IRecord进行变换 <br>
         * @param <T> 表换结果类型
         * @param keys 键名序列,用逗号分隔
         * @param mapper 结果变换函数 rec->t
         * @return pivotTable 的 搜集器
         */
        static <T> Collector<IRecord,List<IRecord>,T> pvtclcL(final String keys,final Function<IRecord,T> mapper){
            return Collector.of( LinkedList::new, List::add, (a, b) -> { a.addAll(b); return a; }
            ,aa->mapper.apply(IRecord.pivotTable(aa,keys,LittleTree::LIST)));
        }
        
        /**
         * Pivot Table 的搜集器：搜集并变换 <br>
         * 根据 keys 做数据 透视，并把中间结果Stream&lt;IRecord&gt;类型, <br>
         * 存入IRecord(以keys为路径维度标记)，最后 使用 mapper 对IRecord进行变换 <br>
         * @param <T> 表换结果类型
         * @param keys 键名序列,用逗号分隔
         * @param mapper 结果变换函数 rec->t
         * @return pivotTable 的 搜集器
         */
        static <T> Collector<IRecord,List<IRecord>,T> pvtclcS(final String keys,final Function<IRecord,T> mapper){
            return Collector.of( LinkedList::new, List::add, (a, b) -> { a.addAll(b); return a; }
            ,aa->mapper.apply(IRecord.pivotTable(aa,keys,stream->stream)));
        }
        
        /**
         * Pivot Table 的搜集器：搜集并变换 <br>
         * 根据 keys 做数据 透视，并把中间结果IRecord[]类型, <br>
         * 存入IRecord(以keys为路径维度标记)，最后 使用 mapper 对IRecord进行变换 <br>
         * @param <T> 表换结果类型
         * @param keys 键名序列,用逗号分隔
         * @param mapper 结果变换函数 rec->t
         * @return pivotTable 的 搜集器
         */
        static <T> Collector<IRecord,List<IRecord>,T> pvtclcA(final String keys,final Function<IRecord,T> mapper){
            return Collector.of( LinkedList::new, List::add, (a, b) -> { a.addAll(b); return a; }
            ,aa->mapper.apply(IRecord.pivotTable(aa,keys,stream->stream.toArray(IRecord[]::new))));
        }
        
        /**
         * Pivot Table 的搜集器：使用示例
         * cph(RPTS(3,L("A","B"))).stream().collect(pvtclc(0,1));
         * @param keys 键名序列,分类层级序列 ， ,键名非String类型的对象，会调用toString给予完成转换。
         * @return pivotTable 的 搜集器
         */
        static Collector<IRecord,List<IRecord>,IRecord> pvtclc(Object... keys){
            
            final var kk = keys== null
                ? new String[] {} // 空的分类层级序列
                : Arrays.stream(keys).map(Object::toString).toArray(String[]::new);// 透视表的层级分类依据
            return Collector.of(LinkedList::new,List::add,(a,b)->{a.addAll(b);return a;}
            ,aa->IRecord.pivotTable(aa,kk,LittleTree::LIST));
        }
        
        /**
         * 转换成一个二维数组：把IRecord视为一个values的LinkedList,将其转换成一维数组，然后再把 rr 集成起来拼装成二维数组。
         * @param rr IRecord的集合
         * @return 二维数组
         */
        static String[][] toStringArray(final List<IRecord> rr){
            return rr.stream().map(IRecord::toStringArray).toArray(String[][]::new);
        }
        
        /**
         * 转换成一个二维数组
         */
        static Object[][] toObjArray(final List<IRecord> rr){
            return rr.stream().map(IRecord::toObjArray).toArray(Object[][]::new);
        }
        
        /**
         * 把一个函数t2u 应用到一个 List<T>类型的容器类型
         * @param <T> 列表的元素的类型
         * @param <U> 函数t2u的返回结果
         * @param t2u 应用到列表上的函数
         * @return 把一个函数应用到 一个LIST
         */
        static <T,U> Function<List<T>,List<U>> applicative(final Function<T, U> t2u){
            return  ll-> ll.stream().map(t2u).collect(Collectors.toList());
        }
        
        /**
         * line 待分解的字符序列 分解成 所有的字串名称。
         * 一般用于数据钻取的分层处理。累加性运算的Key-Value 表达具有普遍意义。
         * 
         * 把 /a/b/c 解析成
         *   /a,/a/b,/a/b/c 的需求
         * @param line 待分解的字符序列 delim 分隔符默认为 "/" 
         * @return 字符串的所有前缀的集合。
         */
        static List<String> split2prefixes(final String line){
            return split2prefixes(line,"/");
        }
        
        /**
         * line 待分解的字符序列 分解成 所有的字串名称。
         * 一般用于数据钻取的分层处理。累加性运算的Key-Value 表达具有普遍意义。
         * 
         * 把 /a/b/c 解析成
         *   /a,/a/b,/a/b/c 的需求
         * @param line 待分解的字符序列
         * @param delim 分隔符
         * @return 字符串的所有前缀的集合。
         */
        static List<String> split2prefixes(final String line, final String delim){
            final var ss = line.split(delim);
            return split2prefixes(ss,delim);
        }
        
        /**
         * 遮住scanl具有相似意义，差别是split2prefixes 返回的是List<字符串> 二者在原理上一致
         * line 待分解的字符序列 分解成 所有的字串名称。
         * 一般用于数据钻取的分层处理。累加性运算的Key-Value 表达具有普遍意义。
         * 
         * 把 [a,b,c] 解析成
         *   /a,/a/b,/a/b/c 的序列，这个对于累加数据的钻取，累加性运算的Key-Value 表达具有普遍意义。
         * @param ss 字符串序列，拼接成前缀字符串
         * @param delim 分隔符,作根节点的分隔符
         * @return 字符串的所有前缀的集合。
         */
        static List<String> split2prefixes(final String[] ss, final String delim){
            final var ll = new LinkedList<String>();
            ll.add(delim);// 加入根节点。
            final var buffer = new StringBuffer();
            Arrays.stream(ss).filter(e->!e.matches("\\s*"))// 去除掉空白的key
            .forEach(s->{
                buffer.append(delim).append(s);
                ll.add(buffer.toString());
            });// 前缀累加
            return ll;
        }
        
        /**
        * 对键值儿进行扫描:
        * 所谓扫描是指 对于 [1,2,3,4] 这样的序列生成 如下的真前缀的集合(不包括空集合)：术语scan 来源于 haskell 语言
        * [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
        * 
        * @param <T> 元素类型
        * @param <U> 变换结果类型
        * @param stream 元素的流数据
        * @param fx 真前缀的变换函数:tt->u
        * @param reverse 是否对数据进行倒转
        * @param include_empty 是否包含空列表。true 表示包含空集合
        * @return List<U>
        */
        @SuppressWarnings("unchecked")
        static <T,U> List<U> scan(final Stream<T> stream, final Function<List<T>, U> fx,
                                  boolean reverse, boolean include_empty) {
            final var uu = new LinkedList<U>();
            if(stream==null)return uu;
            final Function<List<T>,U> final_fx = fx==null? (Function<List<T>,U>)(e->(U)e):fx;
            final var prev = new LinkedList<T>();
            if(include_empty)uu.add(final_fx.apply(LIST(prev)));//包含空列表
            stream.forEach(t->{
                prev.add(t);
                final var pp = LIST(prev);
                if(reverse)Collections.reverse(pp);
                final var u = final_fx.apply(pp);
                uu.add(u);
            });
            
            return uu;
        }
        
       /**
        * 对键值儿进行扫描:
        * 所谓扫描是指 对于 [1,2,3,4] 这样的序列生成 如下的真前缀的集合(不包括空集合)：术语scan 来源于 haskell 语言
        * [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
        * @param <T> 元素类型
        * @param <U> fx:变换结果类型
        * @param stream 元素的流数据
        * @param fx 真前缀的变换函数:tt->u
        * @param reverse 是否对数据进行倒转
        * @return List<U> U的集合
        */
        static <T,U> List<U> scan(final Stream<T> stream, final Function<List<T>, U> fx, boolean reverse) {
            return scan(stream,fx,reverse,false);
        }
        
        /**
         * 对键值儿进行扫描: 所谓扫描是指 对于 [1,2,3,4] 这样的序列生成 如下的真前缀的集合(不包括空集合)：术语scan 来源于 haskell 语言
         * [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
         * 
         * @param <T>    元素类型
         * @param <U>    变换结果类型
         * @param stream 元素的流数据
         * @param fx     真前缀的变换函数:tt->u
         * @return List<U> U 的集合
         */
        static <T, U> List<U> scan(final Stream<T> stream, final Function<List<T>, U> fx) {
            return scan(stream, fx, false);
        }

        /**
         * 强制类型转换函数 <br>
         * 把一个Object 转换目标类型：动用rec2obj的方式进行转换。 <br>
         * 创立一个 key为0的值为为obj的record 然后使用IRecord的类型转换方法进行类型转换。<br>
         * 是 IRecord.rec2obj(REC(0,obj),targetClass); 的简写方式 <br>
         * 由于record 就是模仿 LISP语言中的列表（增强了key-value的树形特征）。<br>
         * 所以 IRecord 理论上是可以标识任何数据结构的(类型)。<br>
         * 所以rec 转换成任意一个对象结构也是可行的。<br>
         * 
         * @param <T>         目标类型数据的class
         * @param targetClass 目标类型
         * @return obj->T 的实例函数
         */
        static <T> Function<Object, T> coerce(final Class<T> targetClass) {
            return obj -> IRecord.obj2target(obj, targetClass);// 创立一个 key为0的值为为obj的recourd 然后使用IRecord的类型转换方法进行类型转换。
        }

        /**
         * 把一个Object 转换目标类型：动用rec2obj的方式进行转换。 <br>
         * 创立一个 key为0的值为为obj的record 然后使用IRecord的类型转换方法进行类型转换。<br>
         * 是 IRecord.rec2obj(REC(0,obj),targetClass); 的简写方式 <br>
         * 由于record 就是模仿 LISP语言中的列表（增强了key-value的树形特征）。<br>
         * 所以 IRecord 理论上是可以标识任何数据结构的(类型)。<br>
         * 所以rec 转换成任意一个对象结构也是可行的。<br>
         * 
         * @param <T>         目标类型数据的class
         * @param obj         源数据类型
         * @param targetClass 目标类型
         * @return T类型数据结果
         */
        static <T> T obj2target(final Object obj, final Class<T> targetClass) {
            return IRecord.rec2obj(REC(0, obj), targetClass);// 创立一个 key为0的值为为obj的recourd 然后使用IRecord的类型转换方法进行类型转换。
        }
        
        /**
         * 把一个record 转换目标类型：由于record 就是模仿 LISP语言中的列表（增强了key-value的树形特征）。<br>
         * 所以 IRecord 理论上是可以标识任何数据结构的。<br>
         * 所以rec 转换成任意一个对象结构也是可行的。<br>
         * 
         * 对于集合类型,如:数组, Collections,Stream,Iterable 只从键值列表中检索是否存在对应的类型给kvp数据，如存在返回对应的value，否则返回null<br>
         * 并不做更为高级的加工处理 <br>
         * 
         * <br>
         * 可以这样理解obj2target<br>
         * 首先 我们把 rec 视为一个 targetClass 的候选值的 集合(KVPair kvp 的值)。<br>
         * 尝试在 用targetClass与kvp中的值进行匹配<br>
         * 如果没有合适类型。我们就把 obj2target 视为  targetClass 的构造函数的参数集合 参数名称就是 kvp的key,<br>
         * 参数值 就是 kvp的value <br>
         * 调用targetClass的默认构造函数使用参数 rec给予初始化进而生成对象。 <br>
         * 
         * @param <T> 目标类型数据的class
         * @param rec IRecord 结构的数据
         * @param targetClass 目标类型,当targetClass 为Object.class 返回rec本省。
         * @return targetClass 的一个实例数据。
         */
        @SuppressWarnings("unchecked")
        static <T> T rec2obj(final IRecord rec, final Class<T> targetClass){
            // IRecord 作为特殊存在，给予直接返回。
            if (targetClass.isAssignableFrom(IRecord.class))return (T)rec;// IRecord 直接返回
            
            if(rec!=null) {// 首先从record 内进行类型检索
                //元素类型提取
                final var opt = rec.stream().map(KVPair::value).filter(Objects::nonNull)
                    .filter((e->targetClass.isAssignableFrom(e.getClass()))).findFirst(); // 寻找一个满足要求类型的字段
                if(opt.isPresent()) return (T)opt.get();
            }// rec
            
            ////////////////////////////////////////////////////////////////////
            // java 基本类型的处理
            ////////////////////////////////////////////////////////////////////
            
            // 布尔类型的处理
            if (targetClass == Boolean.class || targetClass == boolean.class) {// 布尔类型的转换
                // 这是规定。比如 判断表是否存在 "show tables like ''{0}''",不存在的就是返回null,因此作为false;
                if (rec == null) return (T) (Object) false;// 值null 是为false.
                final var value = rec.get(0);// 提取字段的第一项 这个对于 boolean 比较特殊 仅通过 一项 就可以判断出来，就不用 遍历所有字段了。
                if (value == null) {// null 被视为 false
                    return (T) (Object) false;
                } else {// 非空值
                    if (value instanceof String) {// 字符串类型 "false" 视为false,其他视为true
                        final var str = ((String) value).strip().toLowerCase(); // string value
                        try { // 尝试转换成数字然后0是做false,其他视作true
                            final Number number = Double.parseDouble(str);
                            return (T) (Object) (number.intValue() != 0);
                        } catch (NumberFormatException e) {
                            // do nothing
                        } // try
                        return (T) (Object) (!str.equals("false"));
                    } else if (Number.class.isAssignableFrom(value.getClass())) {// 数值类型非0视为true;
                        final var number = (Number) value; // number value
                        return (T) (Object) (number.intValue() != 0);// 非零均视为true
                    } else {// 其他类型均视为true
                        return (T) (Object) true;
                    } // if
                } // if(v==null)
            } // targetClass== Boolean.class
            
            // 把Boolean类型前置再rec==null 就是为了处理 null作为false的理解的情况。
            if(rec==null)return null;// 无效则直接返回。
            
            // 遍历字段 处理基本类型
            for(int i=0;i<rec.size();i++) { // 依次遍历各个字段
                T target = null; //  目标值
                // java 的基本类型的处理
                if(targetClass== Byte.class || targetClass==byte.class) {// 字节类型
                    final var number = rec.num(i); // 提取数字类型的值
                    if(number!=null) target = (T)(Object)(number.byteValue());
                } else if(targetClass== Integer.class||targetClass==int.class) {// 整型
                    final var number = rec.num(i); // 提取数字类型的值
                    if(number!=null) target = (T)(Object)(number.intValue());
                } else if(targetClass== Long.class||targetClass==long.class) {// 长整型
                    final var number = rec.num(i); // 提取数字类型的值
                    if(number!=null) target = (T)(Object)(number.longValue());
                }else if(targetClass== Double.class||targetClass==double.class) {// 双精度
                    final var number = rec.num(i); // 提取数字类型的值
                    if(number!=null) target = (T)(Object)(number.doubleValue());
                }else if(targetClass== Float.class||targetClass==float.class) {// 单精度
                    final var number = rec.num(i); // 提取数字类型的值
                    if(number!=null) target = (T)(Object)(number.floatValue());
                }else if(targetClass== Short.class||targetClass==short.class) {// 短整型
                    final var number = rec.num(i); // 提取数字类型的值
                    if(number!=null) target = (T)(Object)(number.shortValue());
                }else if(targetClass== Character.class||targetClass==char.class) {// 字符型:这里由精度损失。仅用于ascii码
                    final var number = rec.num(i); // 提取数字类型的值
                    if(number!=null) target = (T)(Object)((char)number.byteValue());
                }else if(targetClass== Number.class) {// 数字
                    final var number = rec.num(i); // 提取数字类型的值
                    if(number!=null) target = (T)(Object)(number);
                }else if(targetClass== Date.class) {// 日期类型
                    target = (T)(Object)(rec.date(i));
                }else if(targetClass== LocalDate.class) {// 本地日期
                    target = (T)(Object)(rec.ld(i));
                }else if(targetClass== LocalTime.class) {// 本地时间
                    target = (T)(Object)(rec.lt(i));
                }else if(targetClass== LocalDateTime.class) {//本事日期使劲。
                    target = (T)(Object)(rec.ldt(i));
                }else if(targetClass== Timestamp.class) {// 时间戳类型
                    target = (T)(Object)(rec.timestamp(i));
                }else if (targetClass == String.class) {// 字符串类型
                    target = (T)(Object)(rec.str(i));
                }else if(targetClass== Object.class) {// 对象类型返回本身
                    target = (T)(Object)rec;
                } else if ((targetClass.isAssignableFrom(Collection.class) // 集合类型的判断
                        || targetClass.equals(Stream.class) // 流类型
                        || targetClass.isArray() // 数组
                        || targetClass.isAssignableFrom(Iterable.class) // 迭代类型
                    ) && rec.get(i) != null) {// 对象类型返回本身
                    
                    final var tclass = (Class<T>) rec.get(i).getClass();
                    if (targetClass.isAssignableFrom(tclass)) target = (T) rec.get(i);
                }// if
                
                if(target !=null) return target;
            }// for 字段遍历
            
            ////////////////////////////////////////////////////////////////////
            // JavaBean 对象 的 处理  ： 当 字段逐个遍历之后仍旧找不到 合适的类型 
            // 则 认定 targetClass 是一个复合类型,需要采用构造函数的方式来进行创建
            ////////////////////////////////////////////////////////////////////
            Object javaBean = null;// 目标类型
            try {
                final var ctor = targetClass.getDeclaredConstructor((Class<?>[]) null); // 获取默认构造函数
                ctor.setAccessible(true);// 增强构造函数的访问能力
                javaBean = ctor.newInstance((Object[]) null);// 提取默认构造函数
                IRecord.OBJINIT(javaBean, rec);// 对Javabean 进行实例化(字段初始化)
            } catch (Exception e) {
                if (debug) e.printStackTrace();
            } // try
            
            // 返回结果值
            return (T)javaBean;// 以bean的实例作为对象返回值。
        }// rec2obj
         
        /////////////////////////////////////////////////////////////////////
        // 以下是IRecord 的默认静态函数区域
        /////////////////////////////////////////////////////////////////////
        
        /**
         * 构建一个 IRecord的构建器
         * @param keys 键名序列
         * @return Builder
         */
        static Builder builder(final String keys) {
            return new Builder(keys);
        }

        /**
         * 构建一个 IRecord的构建器
         * @param keys 键名序列
         * @return Builder
         */
        static Builder builder(final String[] keys) {
            return new Builder(keys);
        }

        /**
         * 构建一个 IRecord的构建器
         * @param keys 键名序列
         * @return Builder
         */
        static Builder builder(final List<String> keys) {
            return new Builder(keys);
        }
        
        /**
         * 构建一个 IRecord的构建器
         * @param keys 键名序列
         * @return Builder
         */
        static Builder builder(final Stream<String> keys) {
            return new Builder(keys.toArray(String[]::new));
        }

        /**
         * 构建一个 IRecord的构建器
         * @param recs 键名集合：只提取 recs中的keys,会把 recs 合并成一个 Record 然后提取keys,空值返回一个 空的REC().
         * @return Builder
         */
        static Builder builder(final IRecord... recs) {
            final var rec = REC();
            if(recs!=null)Arrays.stream(recs).forEach(rec::add);
            return new Builder(rec.keys().stream()
                .map(SQL::parseFieldName).map(e->e.str("name")).collect(Collectors.toList()));
        }

        /**
         * 构建一个 IRecord的构建器
         * @param sql named sql 对象，提取其中的 sqlCtx作为键名列表
         * @return Builder
         */
        static Builder builder(final SQL sql) {
            return IRecord.builder(sql.getSqlCtx2());
        }

        /**
         * 构建一个 IRecord的构建器 (builder的别名)
         * @param keys 键名序列
         * @return Builder
         */
        static Builder rb(final String keys) {
            return new Builder(keys);
        }
        
        /**
         * 构建一个 IRecord的构建器 (builder的别名)
         * @param keys 键名序列
         * @return Builder
         */
        static Builder rb(final String[] keys) {
            return IRecord.builder(keys);
        }
        
        /**
         * 构建一个 IRecord的构建器 (builder的别名)
         * @param recs 键名集合：只提取 recs中的keys,会把 recs 合并成一个 Record 然后提取keys,空值返回一个 空的REC().
         * @return Builder
         */
        static Builder rb(final IRecord... recs){
            return builder(recs);
        }
        
        /**
         * 构建一个 IRecord的构建器 (builder的别名)
         * @param sql named sql 对象，提取其中的 sqlCtx作为键名列表
         * @return Builder
         */
        static Builder rb(final SQL sql){
            return IRecord.builder(sql);
        }

        /**
         * 构建一个 IRecord的构建器 (builder的别名)
         * @param keys 键名序列
         * @return Builder
         */
        static Builder rb(final List<String> keys) {
            return IRecord.builder(keys);
        }
        
        /**
         * 采用SQL::parseFieldName 进行字段名处理<br>
         * 构建一个 IRecord的构建器 (builder的别名)
         * @param keys 键名序列,不同键之间用逗号分隔
         * @return Builder
         */
        static Builder rb2(final String keys) {
            return rb2(keys.split("[,]+"));
        }
        
        /**
         * 采用SQL::parseFieldName 进行字段名处理<br>
         * 构建一个 IRecord的构建器 (builder的别名) <br>
         * @param keys 键名序列,不同键之间用逗号分隔
         * @return Builder
         */
        static Builder rb2(final String[] keys) {
            return IRecord.builder(Arrays.stream(keys).map(SQL::parseFieldName).map(e->e.str("name")));
        }

        /**
         * 把一个键值对的数据转换成一个R的类型
         */
        Function<Object, Number> obj2num = obj -> {
            if (obj instanceof Number) return (Number) obj;
            Number num = (Number) Double.parseDouble(obj.toString());
            return num;
        };
        
        /**
         * 把一个键值对的数据转换成一个数字的类型
         */
        Function<KVPair<String,?>,Number> kv2num = (kv)->obj2num.apply(kv.value());
        
        /**
         * 把一个键值对的数据转换成一个数字的类型
         */
        Function<KVPair<String,Object>,Number> kv2num2 = (kv)->obj2num.apply(kv.value());
        
        /**
         * 把一个键值对的数据转换成一个R的类型
         */
        Function<KVPair<String,?>,Integer> kv2int = (kv)->obj2num.apply(kv.value()).intValue();
        
        /**
         * 把一个键值对的数据转换成一个整形的类型
         */
        Function<KVPair<String,Object>,Integer> kv2int2 = (kv)->obj2num.apply(kv.value()).intValue();
        
        /**
         * 把一个键值对的数据转换成一个R的类型
         */
        Function<KVPair<String,?>,Long> kv2lng = (kv)->obj2num.apply(kv.value()).longValue();
        
        /**
         * 把一个键值对的数据转换成一个长整形的类型
         */
        Function<KVPair<String,Object>,Long> kv2lng2 = (kv)->obj2num.apply(kv.value()).longValue();
        
        /**
         * 把一个键值对的数据转换成一个R的类型
         */
        Function<KVPair<String,?>,Double> kv2dbl = (kv)->obj2num.apply(kv.value()).doubleValue();
        
        /**
         * 把一个键值对的数据转换成一个双精度浮点数的类型
         */
        Function<KVPair<String,Object>,Double> kv2dbl2 = (kv)->obj2num.apply(kv.value()).doubleValue();
        
        /**
         * 把一个键值对的数据转换成一个浮点数的类型
         */
        Function<KVPair<String,?>,Float> kv2float = (kv)->obj2num.apply(kv.value()).floatValue();
        
        /**
        * 把一个键值对的数据转换成一个浮点数的类型
        */
        Function<KVPair<String,Object>,Float> kv2float2 = (kv)->obj2num.apply(kv.value()).floatValue();
        
        /**
         * 把一个键值对的数据转换成一个段整形的类型
         */
        Function<KVPair<String,?>,Short> kv2short = (kv)->obj2num.apply(kv.value()).shortValue();
        
        /**
         * 把一个键值对的数据转换成一个短整形的类型
         */
        Function<KVPair<String,Object>,Short> kv2short2 = (kv)->obj2num.apply(kv.value()).shortValue();
        
        /**
         * 把一个键值对的数据转换成一个字节的类型
         */
        Function<KVPair<String,?>,Byte> kv2byte = (kv)->obj2num.apply(kv.value()).byteValue();
        
        /**
         * 把一个键值对的数据转换成一个字节的类型
         */
        Function<KVPair<String,Object>,Byte> kv2byte2 = (kv)->obj2num.apply(kv.value()).byteValue();
        
        /**
         * 把一个键值对的数据转换成一个布尔的类型
         */
        Function<KVPair<String,?>,Boolean> kv2bool = (kv)->Boolean.valueOf(kv.value()+"");
        
        /**
         * 把一个键值对的数据转换成一个布尔的类型
         */
        Function<KVPair<String,Object>,Boolean> kv2bool2 = (kv)->Boolean.valueOf(kv.value()+"");
        
        /**
         * 把一个键值对的数据转换成一个字符的类型
         */
        Function<KVPair<String,Object>,Character> kv2char = (kv)-> (kv.value() + "").charAt(0);
        
        /**
         * 把一个键值对的数据转换成一个字符的类型
         */
        Function<KVPair<String,Object>,Character> kv2char2 = (kv)-> (kv.value() + "").charAt(0);
        
        /**
         * 等价函数
         */
        Function<Object,Object> identity = (Object o)->o;
        
        /**
         * 统计搜集工具
         * @param name 字段名称
         * @return
         */
        static Collector<? super IRecord, ?, DoubleSummaryStatistics> dbl_stats(String name){
            return dbl_stats(e->e.dbl(name));
        }
        
        /**
         * 统计搜集工具
         * @param t2dbl 类型变换函数 把 一个T类型的对象转换成浮点数
         * @return 浮点数的统计器
         */
        static <T> Collector<? super T, ?, DoubleSummaryStatistics> dbl_stats(ToDoubleFunction<T> t2dbl){
            return Collectors.summarizingDouble(t2dbl);
        }
        
        /**
         * 统计搜集工具
         * @param t2dbl 类型变换函数 把 一个KVP类型的对象转换成浮点数
         * @return 浮点数的统计器
         */
        static Collector< KVPair<String,Object>, ?, DoubleSummaryStatistics> dbl_stats2(Function<KVPair<String, Object>, Double> t2dbl){
            return Collectors.summarizingDouble(kv2dbl::apply);
        }
       
        /**
         * 统计搜集工具
         * @param name 字段名称
         * @return 整型统计对象
         */
        static Collector<? super IRecord, ?, IntSummaryStatistics> int_stats(String name){
            return Collectors.summarizingInt(e->e.i4(name));
        }
        
        /**
         * 统计搜集工具
         * @param <T> 源数据对象的类型
         * @param t2int  对象转换成整型的函数
         * @return 整型统计对象
         */
        static <T> Collector<? super T, ?, IntSummaryStatistics> int_stats(ToIntFunction<T> t2int){
            return Collectors.summarizingInt(t2int);
        }

        /**
         * 统计搜集工具
         * @param t2int  kvp对象转换成整型的函数
         * @return 整型统计对象
         */
        static Collector< KVPair<String,Object>, ?, IntSummaryStatistics> int_stats2(Function<KVPair<String, Object>, Integer> t2int){
            return Collectors.summarizingInt(t2int::apply);
        }
        
        /**
         * 统计搜集工具
         * @param name 字段名称
         * @return 长整型统计对象
         */
        static Collector<? super IRecord, ?, LongSummaryStatistics> lng_stats(String name){
            return lng_stats(e->e.i4(name));
        }
        
        /**
         * 统计搜集工具
         * @param t2lng 字段名称
         * @param <T> 列表数据元素的类型
         * @return 长整型统计对象
         */
        static <T> Collector<? super T, ?, LongSummaryStatistics> lng_stats(ToLongFunction<T> t2lng){
            return Collectors.summarizingLong(t2lng);
        }
        
        /**
         * 统计搜集工具
         * @param t2lng 元素变换函数  kvp->long
         * @return 长整型统计对象
         */
        static Collector<KVPair<String,Object>, ?, LongSummaryStatistics> lng_stats2(Function<KVPair<String, Object>, Integer> t2lng){
            return Collectors.summarizingLong(t2lng::apply);
        }
        
        /**
         * List Collector : 对一个 List&lt;T&gt; 进行归纳: ll表示 mapper 是一个流List->U
         * 
         * @param <T>    归纳元素类型
         * @param <U>    返回结果类型
         * @param mapper 列表变换函数 records -> U
         * @reutrn U 类型的对象
         */
        static <T, U> Collector<T, List<T>, U> llclc(final Function<List<T>, U> mapper) {
            return Collector.of(ArrayList::new, List::add, (aa, bb) -> {
                aa.addAll(bb);
                return aa;
            }, mapper);// Collector
        }
        
        /**
         * List Collector : 对一个 List&lt;IRecord&gt; 进行归纳: 不进行数据变换
         * 
         * @param <T> 归纳元素类型
         * @reutrn List&lt;T&gt; T 类型的列表
         */
        static <T> Collector<T, List<T>, List<T>> llclc() {
            return llclc(e -> e);
        }
        
        /**
         * Stream Collector : 对一个 List<T> 进行归纳: ss 表示 mapper 是一个流Stream->U
         * 
         * @param <T>    归纳元素类型
         * @param <U>    返回结果类型
         * @param mapper 流变换函数 records -> U
         * @reutrn U 类型的对象
         */
        static <T, U> Collector<T, List<T>, U> ssclc(final Function<Stream<T>, U> mapper) {
            final Collector<T, List<T>, List<T>> clc = llclc(); // 获取链表归集器
            return Collector.of(clc.supplier(), clc.accumulator(), clc.combiner(), ll -> mapper.apply(ll.stream()));// Collector
        }
        
        /**
         * Array Collector : 对一个 List<T> 进行归纳: ss 表示 mapper 是一个流Stream->U
         * 
         * @param <T>    归纳元素类型
         * @param <U>    返回结果类型
         * @param mapper 流变换函数 tt-> U
         * @reutrn U 类型的对象
         */
        @SuppressWarnings("unchecked")
        static <T, U> Collector<T, List<T>, U> aaclc(final Function<T[], U> mapper) {
            final Collector<T, List<T>, List<T>> clc = llclc(); // 获取链表归集器
            return Collector.of(clc.supplier(), clc.accumulator(), clc.combiner(), ll -> mapper.apply(ll.toArray(n -> {
                final var componentType = ll.stream().filter(Objects::nonNull).findFirst()
                        .map(e -> (Class<T>) e.getClass()).orElse((Class<T>) Object.class);
                return (T[]) Array.newInstance(componentType, n);
            })));// Collector
        }

        /**
         * 把IRecord 集合 [rec] 规约乘一个 IRecord 向量 r,然后 再 调用r2u把r变换成u类型的对象
         *
         * @param <U> 结果类型
         * @param r2u 映射 rec->u
         * @return r2u 类型的归集器
         */
        static <U> Collector<IRecord, List<IRecord>, U> r2uclc(final Function<IRecord, U> r2u) {
            @SuppressWarnings("unchecked")
            final Function<IRecord, U> mapper = r2u == null ? e -> (U) e : r2u;
            final Collector<IRecord, List<IRecord>, List<IRecord>> clc = llclc(); // 获取链表归集器
            return Collector.of(clc.supplier(), clc.accumulator(), clc.combiner(),
                    compose_f(mapper, IRecord::ROWS2COLS));
        }

        /**
         * 把IRecord 集合 [rec] 规约乘一个 IRecord 向量 r,然后 再 调用r2u把r变换成u类型的对象
         *
         * @param <U> 结果类型
         * @param r2u 映射 rec->u
         * @return r2u 类型的归集器
         */
        @SuppressWarnings("unchecked")
        static <U> Collector<KVPair<String, ?>, List<KVPair<String, Object>>, U> r2uclc2(final Function<IRecord, U> r2u) {
            final Function<IRecord, U> mapper = r2u == null ? e -> (U) e : r2u;
            final Function<List<KVPair<String, Object>>, U> kvp2u = compose_f(mapper, IRecord::KVS2REC);

            return Collector.of(() -> new ArrayList<>(), (aa, a) -> aa.add((KVPair<String, Object>) a), (a, b) -> {
                a.addAll(b);
                return a;
            }, kvp2u);
        }

        /**
         * 累加行结构的IRecord并将其转换成列结构的IRecord<br>
         * Collector 变换器。可以把一个IRecord流序列转换成一个IRecord对象<br>
         * 方法示意: cph2(RPTA(3,A(1,2,3))).collect(rclc) 即生成一个数据框/columns结构的IRecord<br>
         */
        Collector<IRecord, List<IRecord>, IRecord> rclc = r2uclc(e -> e);

        /**
         * rclc2 ( rclc2 的后缀2 表示这是一个队KVPair 进行归集的版本 ) <br>
         * 对KVPair&lt;String,?&gt;进行累积并组合成一个IRecord <br>
         * 方法示意: REC("key", A("name","sex","birth"),"value",A("姓名","性别","出生日期")).rcollect2(rclc2); <br>
         * 生成一个 字典对象 { name:姓名	sex:性别	birth:出生日期 }
         */
        Collector<KVPair<String, ?>, List<KVPair<String, Object>>, IRecord> rclc2 = r2uclc2(e -> e);
        
        /**
         * 比较器,需要 键名序列keys中的每个值对象带有比较能力:Comparable
         * @param keys 键名序列，键名之间用 逗号,/,\号进行分隔
         * @return keys 序列的比较器
         */
        public static Comparator<IRecord> cmp(final String keys){
            return IRecord.cmp(keys,true);
        }
        
        /**
         * 比较器,需要 键名序列keys中的每个值对象带有比较能力:Comparable
         * @param keys 键名序列，键名之间用 逗号,/,\号进行分隔
         * @return keys 序列的比较器
         */
        public static Comparator<IRecord> cmp(final String keys,final boolean asc){
            return IRecord.cmp(keys.split("[,/\\\\]+"),asc);
        }
        
        /**
         * 比较器,需要 键名序列keys中的每个值对象带有比较能力:Comparable
         * 
         * @param <T>    元素类型
         * @param <U>    具有比较能力的类型
         * @param keys   keys 键名序列，键名之间用 逗号,/,\号进行分隔
         * @param mapper (key:键名,t:键值)->u 比较能力变换器
         * @param asc    是否升序,true 表示升序,小值在前,false 表示降序,大值在前
         * @return keys 序列的比较器
         */
        public static <T,U extends Comparable<?>> Comparator<IRecord> cmp(final String keys,final BiFunction<String,T,U> mapper,final boolean asc){
            return IRecord.cmp(keys.split("[,/\\\\]+"), mapper, asc);
        }
        
        /**
         * 比较器,需要 键名序列keys中的每个值对象带有比较能力:Comparable
         * @param keys 键名序列
         * @return keys 序列的比较器
         */
        public static Comparator<IRecord> cmp(final List<String> keys){
            return IRecord.cmp(keys,true);
        }
        
        /**
         * 比较器,需要 键名序列keys中的每个值对象带有比较能力:Comparable
         * @param keys 键名序列
         * @return keys 序列的比较器
         */
        public static Comparator<IRecord> cmp(final List<String> keys,final boolean asc){
            return IRecord.cmp(keys.toArray(String[]::new),asc);
        }
        
        /**
         * 比较器,需要 键名序列keys中的每个值对象带有比较能力:Comparable
         * 
         * @param <T>    元素类型
         * @param <U>    具有比较能力的类型
         * @param keys   keys 键名序列
         * @param mapper (key:键名,t:键值)->u 比较能力变换器
         * @param asc    是否升序,true 表示升序,小值在前,false 表示降序,大值在前
         * @return keys 序列的比较器
         */
        public static <T,U extends Comparable<?>> Comparator<IRecord> cmp(final List<String> keys,final BiFunction<String,T,U> mapper,final boolean asc){
            return IRecord.cmp(keys.toArray(String[]::new), mapper, asc);
        }
        
        /**
         * 比较器,需要 键名序列keys中的每个值对象带有比较能力:Comparable
         * @param keys 键名序列
         * @return keys 序列的比较器
         */
        public static Comparator<IRecord> cmp(final String keys[]){
            return IRecord.cmp(keys,true);
        }
        
        /**
         * 比较器,需要 键名序列keys中的每个值对象带有比较能力:Comparable
         * 
         * @param keys 键名序列
         * @param asc  是否升序,true 表示升序,小值在前,false 表示降序,大值在前
         * @return keys 序列的比较器
         */
        public static Comparator<IRecord> cmp(final String keys[], final boolean asc) {
            return cmp(keys, null, asc);
        }
        
        /**
         * 比较器,需要 键名序列keys中的每个值对象带有比较能力:Comparable
         * 
         * @param <T>    元素类型
         * @param <U>    具有比较能力的类型
         * @param keys   键名序列
         * @param mapper (key:键名,t:键值)->u 比较能力变换器
         * @param asc    是否升序,true 表示升序,小值在前,false 表示降序,大值在前
         * @return keys 序列的比较器
         */
        @SuppressWarnings("unchecked")
        public static <T,U extends Comparable<?>> Comparator<IRecord> cmp(final String keys[],final BiFunction<String,T,U> mapper,final boolean asc){
            final BiFunction<String,T,U> final_mapper = mapper == null
                ? (String i,T o) -> (U) o 
                : mapper;
            
            return (a,b)->{
                final var queue = new LinkedList<String>();
                for(var k:keys)queue.offer(k);// 压入队列
                while(!queue.isEmpty()) {
                    final var key = queue.poll(); // 提取队首元素
                    final var ta = (Comparable<Object>)a.get(key,(T t)->final_mapper.apply(key, t));
                    final var tb = (Comparable<Object>)b.get(key,(T t)->final_mapper.apply(key, t));
                    if( ta==null && tb==null )return 0;
                    else if (ta==null) return -1;
                    else if (tb==null) return 1;
                    else {
                        final var ret = ta.compareTo(tb);// 进行元素比较
                        if(ret!=0) return (asc?1:-1)*ret; // 返回比较结果,如果不相等直接返回,相等则继续比计较
                    }//if
                }// while
                return 0;// 所有key都比较完毕,则认为两个元素相等
            };
        }
        
        /**
         * 判断键名key的值是否位于values值之中
         * @param key 键名
         * @param values 值序列
         * @return 判断谓词
         */
        public static Predicate<IRecord> in(final String key,Object ...values){
            return rec->{
                final var v0 = rec.get(key);
                for(var v:values) if(v.equals(v0))return true;
                return false;
            };
        }
        
        /**
         * 判断键名key的值是否不位于values值之中
         * @param key 键名
         * @param values 值序列
         * @return 判断谓词
         */
        public static Predicate<IRecord> notin(final String key,Object ...values){
            return rec->!in(key,values).test(rec);
        }

        /**
         * 字段名判断谓词
         * @param idx 键名索引从0开始
         * @param tester 键值测试器
         * @param <T> 键值类型
         * @return rec->boolean
         */
        static <T> Predicate<IRecord> predicate(final int idx, final Predicate<T> tester){
            return rec->rec.get(idx, tester::test);
        };

        /**
         * 字段名判断谓词
         * @param key 键名
         * @param tester 键值测试器
         * @param <T> 键值类型
         * @return rec->boolean
         */
        static <T> Predicate<IRecord> predicate(final String key, final Predicate<T> tester){
            return rec->rec.get(key, tester::test);
        };

        /**
         * 字段变换器 mapper
         * @param key 键名
         * @param mapper 键值变换器 t->u
         * @param <T> 键值类型
         * @param <U> 结果类型
         * @return rec->boolean
         */
        static <T,U> Function<IRecord,U> mapper(final String key, final Function<T,U> mapper){
            return rec->rec.get(key, mapper);
        };

        /**
         * 字段变换器 mapper
         * @param idx 键名索引从0开始
         * @param mapper 键值变换器 t->u
         * @param <T> 键值类型
         * @param <U> 结果类型
         * @return rec->boolean
         */
        static <T,U> Function<IRecord,U> mapper(int idx,Function<T,U> mapper){
            return rec->rec.get(idx , mapper);
        };

        /**
         * 判断键名key的值是否满足于predicate
         * @param <T> predicate 的参数类型
         * @param key 键名
         * @param predicate 判断谓词
         * @return 判断谓词
         */
        public static <T> Predicate<IRecord> test(final String key,final Predicate<T> predicate){
            return IRecord.predicate(key, predicate);
        }

        /**
         * 判断键名key的值是否不满足于predicate
         * @param <T> predicate 的参数类型
         * @param key 键名
         * @param predicate 判断谓词
         * @return 判断谓词
         */
        @SuppressWarnings("unchecked")
        static <T> Predicate<IRecord> test2(final String key, final Predicate<T> predicate){
            return rec->!predicate.test((T)rec.get(key));
        }
        
       /**
        * 行数据的子集函数<br>
        * 视rec为一个[rec]的行集合然后用predicate进行过滤 <br>
        * @param predicate 行数据过滤条件
        * @return rec->[rec]
        */
       static Function<IRecord,Stream<IRecord>> subset(final Predicate<IRecord> predicate){
           return rec->rec.rows2(predicate);
       }
       
        /**
         * flagbools 在一个bool向量中 进行标记。
         * 标志向量设置函数在一个 长度为n的全为b值的向量数组中[b,b,b,...,b]的 index 位置进行取反, 比如：<br>
         * flag(false,2,3).apply(5) 返回[false, false, true, true, false]
         * flag(true,2,3).apply(5) 返回[true, true, false, false, true]
         *
         * @param b       标志向量的默认值:true,false
         * @param indexes 标记的索引位置: 从0开始
         * @return 标记向量生成函数 ,(n:标志向量长度)->[b]
         */
        static Function<Integer, Boolean[]> flagbools(Boolean b, Integer... indexes) {
            return n -> {
                if (n <= 0) return new Boolean[0];
                final var notb = !b;
                final var bb = new Boolean[n];
                Arrays.fill(bb, b);
                for (final var idx : indexes) bb[Math.abs(idx) % n] = notb;
                return bb;
            };
        }
        
        /**
         * IRecord 的内部构建器 <br>
         * 创建一个IRecord对象 一共分两步:<br>
         * 1、先指定键名序列 <br>
         * 2、然后再指定值序列 <br>
         * 
         * @author gbench
         *
         */
        class Builder{
            /**
             * 构造函数
             * @param keys 字段键名 列表
             */
            public Builder(final String[] keys) {
                this.keys = keys;
            }

            /**
             * 构造函数
             * @param keys 字段键名 列表
             */
            public Builder(final List<String> keys) {
                this(keys.toArray(String[]::new));
            }

            /**
             * 构造函数
             * @param keys 字段键名 列表, 键名之间采用逗号分隔
             */
            public Builder(final String keys) {
                this(keys.split("[,]+"));
            }

            /**
             * 根据值序列建立一个IRecord记录结构
             * 
             * @param <T>     参数数组的 元素类型
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            @SafeVarargs
            public final <T> IRecord get(final T... objects) {
                return this.internal_get((Object[]) objects);
            }

            /**
             * 根据值序列建立一个IRecord记录结构
             *
             * @param <T>     参数数组的 元素类型
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            public final <T> IRecord get(final Stream<T> objects) {
                return this.internal_get((Object[]) objects.toArray());
            }

            /**
             * 根据值序列建立一个IRecord记录结构
             *
             * @param <T>     参数数组的 元素类型
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            public final <T> IRecord get(final Collection<T> objects) {
                return this.internal_get((Object[]) objects.toArray());
            }

            /**
             * 根据值序列建立一个IRecord记录结构 (get的 别名函数),非多态只有一个build,以方便使用lambda
             *
             * @param <T>     参数数组的 元素类型
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            @SafeVarargs
            public final <T> IRecord build(final T... objects) {
                return this.get(objects);
            }

            /**
             * 采用SQL::parseFieldName 进行字段名处理<br>
             * 根据值序列建立一个IRecord记录结构
             * 
             * @param <T>     参数数组的 元素类型
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            @SafeVarargs
            public final <T> IRecord get2(final T... objects) {
                return this.internal_get2((Object[]) objects);
            }

            /**
             * 采用SQL::parseFieldName 进行字段名处理<br>
             * 根据值序列建立一个IRecord记录结构
             *
             * @param <T>     参数数组的 元素类型
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            public final <T> IRecord get2(final Stream<T> objects) {
                return this.internal_get2((Object[]) objects.toArray());
            }

            /**
             * 采用SQL::parseFieldName 进行字段名处理<br>
             * 根据值序列建立一个IRecord记录结构
             *
             * @param <T>     参数数组的 元素类型
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            public final <T> IRecord get2(final Collection<T> objects) {
                return this.internal_get2((Object[]) objects.toArray());
            }

            /**
             * 采用SQL::parseFieldName 进行字段名处理<br>
             * 根据值序列建立一个IRecord记录结构 (get2的 别名函数),非多态只有一个build,以方便使用lambda
             *
             * @param <T>     参数数组的 元素类型
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            @SafeVarargs
            public final <T> IRecord build2(final T... objects) {
                return this.get2(objects);
            }

            /**
             * 绘制构建器中的键名序列
             * 
             * @return 键名序列
             */
            public String[] getKeys() {
                return this.keys;
            }
            
            /**
             * 根据值序列建立一个IRecord记录结构
             * 
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            private IRecord internal_get(final Object[] objects) {
                return internal_build(keys, objects);
            }

            /**
             * 根据值序列建立一个IRecord记录结构
             * 
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            private IRecord internal_get2(final Object[] objects) {
                final var kk = Arrays.stream(keys).map(SQL::parseFieldName).map(e -> e.str("name"))
                        .toArray(String[]::new);
                return internal_build(kk, objects);
            }

            /**
             * 根据值序列建立一个IRecord记录结构
             * 
             * @param objects 值序列，与键名按次序一一对应,对于 不足keys长度的值采用类似于R语言的循环遍历objects的方式进行重复利用
             * @return IRecord 记录对象
             */
            private static IRecord internal_build(final String[] keys, final Object[] objects) {
                
                final var rec = REC();
                if (keys == null || keys.length < 1 || objects == null || objects.length < 1)
                    return rec;
                final var n = objects.length;
                for (int i = 0; i < keys.length; i++) {
                    rec.add(keys[i], objects[i % n]);
                }
                
                return rec;
            }

            private final String[] keys;// 键名序列
        }
        
        String SHARP_VARIABLE_PATTERN="#([a-zA-Z_][a-zA-Z0-9_]*)";// sharp 变量的此法模式
        
    }

    /**
     * TreeRecord 区分对key的名称区分大小写
     * @author gbench
     *
     */
    public static abstract class AbstractMapRecord implements IRecord{

        /**
         * 返回自身便于实现链式编程
         */
        @Override
        public IRecord add(Object key, Object value) {
            data.put(key.toString(), value);
            return this;
        }

        @Override
        public IRecord set(String key, Object value) {
            data.put(key, value);
            return this;
        }

        @Override
        public Object get(String key) {
            if(key==null)return null;
            Object o = data.get(key);
            if(o==null) {// 忽略大小写
                Optional<String> k = data.keySet().stream()
                        .filter(key::equalsIgnoreCase).findFirst();
                return k.isPresent()?data.get(k.get()):null;
            }//if
            return o;
        }

        @Override
        public List<Object> gets(String key) {
            return Collections.singletonList(this.get(key));
        }

        @Override
        public Stream<KVPair<String, Object>> stream() {
            return data.entrySet().stream()
                    .map(e-> new KVPair<>(e.getKey(), e.getValue()));
        }

        @Override
        public List<KVPair<String, Object>> kvs() {
            return this.stream().collect(Collectors.toList());
        }

        /**
         * 字符串格式化
         */
        public String toString() {
            final var builder = new StringBuilder();
            final Function<Object,String> cell_formatter = v->{
                if(v==null) return"(null)";
                var line = "{0}";// 数据格式化
                if(v instanceof Date) {
                    line = "{0,Date,yyyy-MM-dd HH:mm:ss}"; // 时间格式化
                }else if(v instanceof Number) {
                    line = "{0,Number,#}"; // 数字格式化
                }//if
                return MessageFormat.format(line, v);
            };// cell_formatter
            
            if(this.data!=null) {
                this.data.forEach((k,v)-> builder.append(k).append(":").append(cell_formatter.apply(v)).append("\t"));
            }
            
            return builder.toString().trim();
        }
        
        /**
         *
         */
        public Map<String,Object> toMap(){
            return this.data;
        }

        private static final long serialVersionUID = -6173203337428164904L;
        protected Map<String,Object> data= null;// 数据信息,使用TreeMap 就是为了保持key的顺序
    } // AbstractMapRecord 

    /**
     * LinkedRecord 区分对key的名称区分大小写 <br>
     * 注意:LinkedRecord 采用默认的 hashcode(地址哈希)以及地址比较的equals,这样做的目的就是:使得<br>
     * Map&lt;IRecord,?&gt; 即以 LinkedRecord 为键类型的 HashMap可以拥有重复的键值,而这对于<br>
     * 同名键比如:Neo4jApp的graph系函数来说<br>
     * 即同名边的属性信息集的生成是很有必要的，特此给与提醒<br>
     * 判断两个LinkedRecord可以采用 comparedTo 是否等于0来进行比较。
     * 
     * @author gbench
     *
     */
    public static class LinkedRecord extends AbstractMapRecord implements IRecord{

        /**
         * 序列构造函数
         * 
         * @param oo 键值序列 :k0,v0,k1,v1,...
         */
        public LinkedRecord(final Object... oo) {
            if (data == null) {
                data = new LinkedHashMap<>();
            }

            for (int i = 0; i < oo.length; i += 2) {
                data.put(oo[i] + "", i < oo.length - 1 ? oo[i + 1] : null);
            }
        }// 键值序列构造函数

        /**
         * 默认构造函数
         */
        public LinkedRecord() {
            data = new LinkedHashMap<>();
        }

        /**
         * 使用map来初始化记录对象：Record 存储一个对initData对象的拷贝。
         * 
         * @param initData 记录对象初始化:
         */
        public LinkedRecord(final Map<String, ?> initData) {
            Map<String, Object> oo = new LinkedHashMap<>();
            if (initData != null)
                oo.putAll(initData);
            data = initData != null ? oo : new LinkedHashMap<>();
        }

        /**
         * 建立以keys为字段的记录对象，并且每个key的值采用initData中对应键值的值进行初始化 <br>
         * 当map中出现不再keys中出现的记录数据，给予舍弃，即LinkedRecord是严格 按照keys的结构进行构造 <br>
         * 
         * @param keys     字段序列
         * @param initData 默认值集合。超出keys中的数据将给予舍弃
         */
        public LinkedRecord(final List<String> keys, final Map<String, ?> initData) {
            this.intialize(keys, initData);
        }

        /**
         * 建立以keys为字段的记录对象，并且每个key的值采用initData中对应键值的值进行初始化 <br>
         * 当map中出现不再keys中出现的记录数据，给予舍弃，即LinkedRecord是严格 按照keys的结构进行构造 <br>
         * 
         * @param keys     字段序列
         * @param initData 默认值集合。超出keys中的数据将给予舍弃
         */
        public LinkedRecord(final String keys[], final Map<String, ?> initData) {
            this.intialize(Arrays.asList(keys), initData);
        }

        /**
         * 建立以keys为字段的记录对象，并且每个key的值采用initData中对应键值的值进行初始化 <br>
         * 当map中出现不再keys中出现的记录数据，给予舍弃，即LinkedRecord是严格 按照keys的结构进行构造 <br>
         * 
         * @param keys     字段序列,使用逗号进行分隔
         * @param initData 默认值集合。超出keys中的数据将给予舍弃
         */
        public LinkedRecord(final String keys, final Map<String, ?> initData) {
            if (keys == null) {
                this.data = new LinkedHashMap<>();
            } else {
                this.intialize(Arrays.asList(keys.split("[,]+")), initData);
            }
        }

        /**
         * 建立以keys为字段的记录对象，并且每个key额值采用map中对应键值的值进行初始化 <br>
         * 当map中出现不再keys中出现的记录数据，给予舍弃，即LinkedRecord是严格 按照keys的结构进行构造 <br>
         * 
         * @param keys 字段序列
         * @param map  默认值集合。超出keys中的数据将给予舍弃
         */
        public void intialize(final List<String> keys, final Map<String, ?> map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> initData = (Map<String, Object>) (map != null ? map : new LinkedHashMap<>());// 初始数据
            data = new LinkedHashMap<>();
            if (keys == null || keys.size() <= 0) {
                // do nothing
            } else {// 仅当keys 有效是才给予字段初始化
                keys.stream().filter(Objects::nonNull)
                    .forEach(key -> data.computeIfAbsent(key, k -> initData.getOrDefault(k, "-")));
            } // if
        }
        
        /**
         * 复制一个 Record 对象
         */
        @Override
        public IRecord duplicate() {
            return new LinkedRecord(this.data);
        }

        /**
         * 数据便历
         * 
         * @param bicons 二元接收函数 (k,v)->{}
         */
        public void forEach(final BiConsumer<? super String, ? super Object> bics) {
            this.data.forEach(bics);
        }

        /**
         * 使用map来初始化记录对象,注意这里是直接使用把 initData来给予包装的。：这是一种快速构造方法。<br>
         * 但会造成实际结构不是LinkedMap,这个适合于属性名称不重要的情况。比如以集合的形式来统一传递参数。 <br>
         * 
         * @param initData 记录对象初始化
         */
        @SuppressWarnings("unchecked")
        public static LinkedRecord of(final Map<?, ?> initData) {
            final var rec = new LinkedRecord();
            rec.data = (Map<String, Object>) initData;
            return rec;
        }

        /**
         * 使用recB 来覆盖recA merged recA 和 recB 的各个各个属性的集合。
         * 
         * @param recA 第一个IRecord
         * @param recB 将要覆盖中的属性的数据,会利用recB中空值覆盖a中的空值
         * @return merged recA 和 recB 的各个各个属性的集合。这是一个新生成的数据对象，该操作不会对recA 和 recB 有任何涌向
         */
        public static IRecord extend(final IRecord recA, final IRecord recB) {
            final IRecord rec = new LinkedRecord();//
            if (recA != null) {
                recA.kvs().forEach(kv -> rec.add(kv.key(), kv.value()));
            }
            if (recB != null) {
                recB.kvs().forEach(kv -> rec.set(kv.key(), kv.value()));
            }
            return rec;
        }
        
        private static final long serialVersionUID = 1060363673536668645L;
    } // LinkedRecord
    
    /**
     * DataFrame 数据框，(key,[v0,v1,...]) 结构的键值对集合 kvs 即值元素为集合类型的KVPs.<br>
     * 术语来源于R，<r>
     * 
     * @author gbench
     *
     */
    public static class DataFrame extends LinkedRecord {
        
        /**
         * 数据格式化
         */
        public String toString() {
            return this.toString2(frt(2));
        }

        /**
         * DataFrame 构造一个数据框对象
         * @param objects 键值序列 key0,value0,key1,value1
         * @return DataFrame  对象
         */
        public static DataFrame DFM(final Object ... objects ) {
            final var n = objects.length;
            final var rec = new DataFrame();
            for(int i=0;i<n-1;i+=2)rec.add(objects[i].toString(),objects[i+1]);
            return rec;
        }
        
        private static final long serialVersionUID = 1L;
    }// class DataFrame

    /**
     * TreeRecord 区分对key的名称区分大小写
     * @author gbench
     *
     */
    public static class TreeRecord extends AbstractMapRecord implements IRecord{

        /**
         * 字段构造函数，只能put存放在keys中的字段
         * @param keys 键使用,分割
         */
        public TreeRecord(String keys) {
            this.intialize(Arrays.asList(keys.split("[,]+")));
        }

        /**
         * 字段构造函数，只能put存放在keys中的字段
         * @param keys 键使用,分割
         */
        public TreeRecord(List<String> keys) {
            this.intialize(keys);
        }

        public TreeRecord(Comparator<String> comparator) {
            data = new TreeMap<>(comparator);
            this.comparator = comparator;
        }

        public TreeRecord(String[] keys) {
            this.intialize(Arrays.asList(keys));
        }

        /**
         * 按照字键名出现次序生成比较器
         * @param keys 键名序列
         */
        public void intialize(List<String> keys) {
            // 比较器
            Comparator<String> comparator = (a,b)->{
                int ret = 0;// 比较结果
                int i = 0;// 键名编号
                Map<String,Integer> map = new HashMap<>();
                for(String s:keys)map.put(s, i++);
                try{ret = map.get(a)-map.get(b);}catch(Exception e) {
                    System.out.println("a:"+a+"\nb:"+b+
                        ",没有出现在 键名列表中："+
                        map+"\n 无法进行数据判断");
                    e.printStackTrace();
                }// try
                return ret;
            };

            data = new TreeMap<>(comparator);
            this.comparator = comparator;
        }

        /**
         * 复制克隆
         * @return
         */
        public IRecord duplicate() {
            final TreeRecord rec = this.imitate();
            this.kvs().forEach(kv-> rec.set(kv.key(), kv.value()));
            return rec;
        }

        public Comparator<String> getComparator(){
            return this.comparator;
        }

        /**
         * 仿制就是为了重用原来的比较器
         * @return
         */
        public TreeRecord imitate() {
            return new TreeRecord(comparator);
        }

        private static final long serialVersionUID = 5297462049239467986L;
        private Comparator<String> comparator = null; // 比较器
    } // TreeRecord

    /**
     * 简单的记录类型,特点就是 键名可以重复
     * @author gbench
     *
     */
    public static class SimpleRecord implements IRecord {

        /**
         * 复制克隆
         * 
         * @return IRecord 的克隆
         */
        public IRecord duplicate() {
            SimpleRecord rec = new SimpleRecord();
            this.kvs().forEach(kv->rec.set(kv.key(),kv.value()));
            return rec;
        }

        /**
         * 添加一个键值，如果存在则添加一个重复的键
         * 
         * @return IRecord 对象本身
         */
        @Override
        public IRecord add(final Object key, final Object value) {
            kvs.add(new KVPair<>(key.toString(), value));
            return this;
        }

        /**
         * 设置键值key的值,如果键值已经存在则修改，否则添加
         * 
         * @return IRecord 对象本身
         */
        @Override
        public IRecord set(final String key, final Object value) {
            final var kp = this.kvs().stream().filter(kv -> kv.key().equals(key)).findFirst();
            if (kp.isPresent())
                kp.get().value(value);
            else
                kvs.add(new KVPair<>(key, value));

            return this;
        }

        /**
         * 忽略key的大小写，相同key仅寻找第一项
         * 
         * @param key 键值表
         * @return key 所对应的值元素
         */
        @Override
        public Object get(final String key) {
            final Optional<KVPair<String, Object>> opt = this.kvs.stream()
                    .filter(e -> e.key().equalsIgnoreCase(key))
                    .findFirst();
            if (opt.isPresent()) {
                return opt.get().value();
            } else {
                return null;
            }
        }

        /**
         * 忽略key的大小写，相同key仅寻找第一项
         * 
         * @param key 键值表
         * @return 对象的key所对应的说有值
         */
        @Override
        public List<Object> gets(final String key) {
            final List<Object> ll = this.kvs.stream()
                .filter(e->e.key().equalsIgnoreCase(key))
                .map(KVPair::value)
                .collect(Collectors.toList());
            return ll;
        }

        /**
         * 键值对的列表
         * @return 键值对的列表
         */
        @Override
        public List<KVPair<String, Object>> kvs() {
            return kvs;
        }

        /**
         * 键值对儿的流
         * 
         * @return Stream<KVPair<String,Object>> 的流
         */
        @Override
        public Stream<KVPair<String, Object>> stream() {
            return kvs.stream();
        }

        /**
         * hashCode
         * 
         * @return hashCode
         */
        @Override
        public int hashCode() {
            return this.toString().hashCode();
        }

        /**
         * 等价判断算法
         * 
         * @param obj 另一个比较对象
         * @return 等价判断算法
         */
        public boolean equals(final Object obj) {
            return this.toString().equals(obj.toString());
        }

        /**
         * 转换成{(String,Object)} 类型的Map
         * 
         * @return {(String,Object)} 类型的Map
         */
        @Override
        public Map<String, Object> toMap() {
            Map<String, Object> map = new LinkedHashMap<>();
            this.kvs().forEach(kv -> map.put(kv.key(), kv.value()));
            return map;
        }

        /**
         * 字符串格式化
         */
        @Override
        public String toString() {
            return this.kvs().stream().map(e->e.key()+":"+e.value())
                .collect(Collectors.joining(","));
        }

        /**
         * 获取指定键值中的数据的第一条
         * 
         * @param recs  记录集合：查找范围
         * @param key   键名
         * @param value 键值
         * @return 记录信息
         */
        public static Optional<IRecord> fetchOne(final List<IRecord> recs, final String key,Object value) {
            return recs.stream().filter(e->e.get(key).equals(value)).findFirst();
        }

        /**
         * 获取指定键值中的数据的第一条
         * 
         * @param recs  记录集合：查找范围
         * @param key   键名
         * @param value 键值
         * @return 记录信息
         */
        public static List<IRecord> fetchAll(final List<IRecord> recs,final String key, final Object value) {
            
            return recs.stream()
                .filter(e->e.get(key).equals(value))
                .collect(Collectors.toList());
        }

        /**
         * 使用recB 来覆盖recA merged recA 和 recB 的各个各个属性的集合。
         * 
         * @param recA
         * @param recB 将要覆盖中的属性的数据,会利用recB中空值覆盖a中的空值
         * @return merged recA 和 recB 的各个各个属性的集合。这是一个新生成的数据对象，该操作不会对recA 和 recB 有任何涌向
         */
        public static IRecord extend (final IRecord recA,final IRecord recB) {
            IRecord rec = new SimpleRecord();//
            if(recA!=null) {recA.kvs().forEach(kv-> rec.add(kv.key(), kv.value()));}
            if(recB!=null) {recB.kvs().forEach(kv-> rec.set(kv.key(), kv.value()));}
            return rec;
        }

        /**
         * 创造一个Record对象,参数分别是：键名1,键值1,键名2,键值2,。。。的序列。
         * 
         * @param values 键值序列
         * @return SimpleRecord 的序列结构可以含有重复的键名
         */
        public static SimpleRecord REC2(final List<?> values) {
           return _REC2(values.toArray());
        }
        
        /**
         * 创造一个Record对象,参数分别是：键名1,键值1,键名2,键值2,。。。的序列。
         * 
         * @param values 键值序列
         * @return SimpleRecord 的序列结构可以含有重复的键名
         */
        public static SimpleRecord REC2(final Stream<?> values) {
           return _REC2(values.toArray());
        }

        /**
         * 创造一个Record对象,参数分别是：键名1,键值1,键名2,键值2,。。。的序列。
         * 
         * @param values 键值序列
         * @return SimpleRecord 的序列结构可以含有重复的键名
         */
        public static SimpleRecord REC2(final Object ... values) {
           return _REC2(values);
        }
        
        /**
         * 解释字符串生成SimpleRecord
         * 
         * @param jsonstr json格式的对象描述
         * @return IRecord 对象
         */
        @SuppressWarnings("unchecked")
        public static SimpleRecord REC2(final String jsonstr){
            final ObjectMapper mapper = new ObjectMapper();
            final SimpleRecord rec = new SimpleRecord();
            if (jsonstr == null || jsonstr.matches("\\s*")) return rec;
            var json = jsonstr.trim();
            if (!json.startsWith("{")) json = "{" + json;// 补充开头的"{"
            if (!json.endsWith("}")) json = json + "}";// 补充结尾的"{"
            try {
                mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
                mapper.readValue(json, Map.class).forEach((k, v) -> rec.add(k + "", v + ""));
            } catch (IOException e) {
                e.printStackTrace();
            }

            return rec;
        }

        /**
         * 创造一个Record对象,参数分别是：键名1,键值1,键名2,键值2,。。。的序列。
         * 
         * @param values 键值序列
         * @return SimpleRecord 的序列结构可以含有重复的键名
         */
        public static SimpleRecord _REC2(final Object[] values) {
            final SimpleRecord rec = new SimpleRecord();
            if(values==null)return rec;
            for (int i = 0; i < values.length; i += 2) {
                final String key = values[i] + "";// 键值名
                final Object value = (i + 1) < values.length ? values[i + 1] : null;// 如果最后一位是key则它的value为null
                rec.add(key, value);
            } // for
            return rec;
        }

        /**
         * 创造一个Record对象,参数分别是：kvp0,kvp1,kvp2,。。。的序列流。
         * 
         * @param kvps 键值序列流
         * @return SimpleRecord 的序列结构可以含有重复的键名
         */
        public static SimpleRecord KVS2REC(final Stream<? extends KVPair<String, ?>> kvps) {
            final var rec = new SimpleRecord();
            kvps.forEach(kvp -> rec.add(kvp.key(), kvp.value()));
            return rec;
        }

        /**
         * 创造一个Record对象,参数分别是：kvp0,kvp1,kvp2,。。。的序列。
         * 
         * @param kvps 键值序列
         * @return SimpleRecord 的序列结构可以含有重复的键名
         */
        @SuppressWarnings("unchecked")
        public static SimpleRecord KVS2REC(final Collection<? extends KVPair<String, ?>> kvps) {
            final var rec = new SimpleRecord();
            rec.kvs.addAll((Collection<KVPair<String, Object>>)(Object)kvps);
            return rec;
        }

        private static final long serialVersionUID = 1L;
        private final List<KVPair<String, Object>> kvs = new LinkedList<>();
    } // SimpleRecord

    /**
     * 树结构的节点。<br>
     * Node 节点为 record的值类型 做了特殊设计(根据record的键值对儿来获取节点名称,默认按顺序提取 name,path,Activity字段值作为getName的返回这)，不过也可以用于非IRecord的值类型 <br>
     * 注意:<br>
     * 由于Node考虑到通用性 在实现 equals做了 路径的遍历处理。这是一种效率很低的 方法。 在具体使用情形中可对Node进行继承而特化出一个简单的版本，来提高效率。<br>
     * 例如:<br>
     *  &#47;&#42;&#42;<br>
     *  &#42; 默认的Node对equals 以及  hashcode 的实现太过繁琐  因此这里给予 实现一个简单版本。 <br>
     *  &#42; 去除了很多通用条件 仅仅用于一个 临时基于Elem&lt;String&gt;本地化的实现。用特化来提高<br> 
     *  &#42; 特化：子类化一个Node用于对实现Node的equals比较 <br>
     *  &#42;&#47;<br>
     *  final var quicknode_counter = new AtomicInteger(0);// quicknode_counter 的唯一标识申城器 <br>
     *  final class QuickNode extends Node&lt;Elem&lt;String&gt;&gt; { <br>
     *      //constructor <br>
     *      public QuickNode(final Elem &lt;String &gt; value) { <br>
     *          super(value); <br>
     *      } <br>
     *      <br>    
     *      &#64;Override <br>
     *      public int hashCode() { <br>
     *          return id; <br>
     *      } <br>
     *      <br>       
     *      &#64;Override <br>
     *      public boolean equals(final Object obj) { <br>
     *          if(obj==null)return false; <br>
     *          return obj.getClass()== QuickNode.class? ((QuickNode)obj).id==(this.id):false; <br>
     *      } <br>
     *      <br>       
     *      &#64;Override <br>
     *      public String getName() { // c重写名称获取函数 <br>
     *          return this.getValue()._1(); <br>
     *      } <br>
     *      <br>      
     *      private final int id = quicknode_counter.getAndIncrement();// 本地节点标识 <br>
     *  }// QuickNode <br>
     * 
     * @author gbench
     *
     * @param <T> 节点中的元素的类型
     */
    public static class Node<T>{
        /**
         * 拷贝钩爪函数
         * @param node
         */
        public Node(final Node<T> node) {
            this.value = node.value;
            this.properties = node.properties;
            this.children = node.children;
            this.lambda_name = node.lambda_name;
            this.parent = node.parent;
        }

        /**
         * 节点的值
         * @param value 节点的值
         */
        public Node(T value){
            this.value = value;
        }

        /**
         * 构造函数 含有名称解析器
         * @param value 节点的值
         * @param lambda_name 节点的名称获取函数: node->String
         */
        public Node(final T value,final Function<Node<T>,String> lambda_name){
            this.value = value;
            this.lambda_name = lambda_name;
        }
        
        /**
         * 克隆函数
         */
        @Override
        public Node<T> clone(){
            return new Node<>(this);
        }

        /**
         * 获取节点的值信息
         * @return 节点的值对象
         */
        public T getValue() {
            return value;
        }
        
        /**
         * 获取节点的值信息
         * 
         * @param <U> 结果类型
         * @param mapper 值的结果变换
         * @return U 类型的结果
         */
        public <U> U getValue(Function<T,U> mapper) {
            return mapper.apply(value);
        }
        
        /**
         * 设置lambda_name的选项
         * @param lambda_name 名称函数的生成表达式。
         * @return 节点对象本身 用于实现链式编程
         */
        public Node<T> setLambdaName(final Function<Node<T>,String>lambda_name){
            this.lambda_name = lambda_name;
            return this;
        }

        /**
         * 简单的额取值写法
         * getValue 的别名
         * @return 节点的值对象
         */
        public T val() {
            return getValue();
        }

        /**
         * 返回节点自身，以便实现链式编程
         * @param value 待设置的节点的值
         * @return 返回节点自身，以便实现链式编程
         */
        public Node<T> setValue(T value) {
            this.value = value;
            return this;
        }

        /**
         * 简单的额设置值的写法
         * setValue 的别名
         * @return 返回节点自身，以便实现链式编程
         */
        public Node<T> val(T value) {
            return this.setValue(value);
        }

        /**
         * 简单的额设置值的写法
         * @param fld_picker 值字段的提取器
         * @return 返回节点自身，以便实现链式编程
         */
        public <U> U val(Function<T,U> fld_picker) {
            return fld_picker.apply(this.getValue());
        }

        /**
         * 获得节点名称，节点名是通过信息值进行访问的。
         *   nameit 根据节点生成对应的名字
         * @return 获取产品名称
         */
        public String getName(final Function<Node<T>,String> nameit) {
            return nameit.apply(this);
        }

        /**
         * 获得节点名称，节点名是通过信息值进行访问的。
         * @param nameflds 可能表示名字的字段名:比如  【“name”,“path”,“Activity”】 的字符串数组
         * @return 节点的名称 如果是视IRecord类型的值对象，首先尝试获取IRecord的path属性，<br>
         * 如果path不存在尝试获取 name属性，如果 仍旧不存在在，就按照一般值对象进行处理器，即把节点值得字符串给予返回。
         */
        public String getName(final String[]nameflds) {
            if(lambda_name!=null) {
                return lambda_name.apply(this);
            }else {
                if(value instanceof IRecord) {
                    final IRecord rec = ((IRecord) value);
                    Object name = null;// name 字段的值
                    if(nameflds!=null)for(final var fld:nameflds) {// 尝试提取默认的名字字段，
                        if((name = rec.get(fld))!=null)break;
                    }//for
                    
                    if(name!=null)
                        return name+"";
                    else
                        return value+"";
                }else {
                    return value+"";
                }//if value
            }// lambda_name
        }

        /**
         * 获得节点名称，节点名是通过信息值进行访问的。
         * 
         * @return 节点的名称 如果是视IRecord类型的值对象，首先尝试获取IRecord的path属性，默认把 name,path,Activity 顺序提取 名称<br>
         * 如果path不存在尝试获取 name属性，如果 仍旧不存在在，就按照一般值对象进行处理器，即把节点值得字符串给予返回。
         */
        public String getName() {
            final var nameflds = new String[] {
                "name","path","Activity"
            };
            return this.getName(nameflds);// 默认可能的用于名字的字段)
        }
        
        /**
         * 获取节点的父节点，根节的父节点为null
         * @return 返回父节点
         */
        public Node<T> getParent(){
            return this.parent;
        }

        /**
         * 获得节点路径
         * @return 从根节点到当前节点的路径
         */
        public String getPath() {
            return this.getPath(this);
        }
        
        /**
         * 获得节点路径
         * @param name_mapper 节点名称变换器 : node->String
         * @return 从根节点到当前节点的路径
         */
        public String getPath(final Function<Node<T>,String> name_mapper) {
            return this.getPath(this,name_mapper);
        }
        
        /**
         * 获取节点路径
         * @return 节点路径
         */
        public Stream<Node<T>> getPathNodes(){
            return Node.getPathNodes(this);
        }
        
        /**
         * 获取节点路径的编码
         * @param start 开始位置
         * @return 节点路径的编号
         */
        public String getPathCode(int start){
            return this.getPathNodes().map(e->String.valueOf(e.getIndex()+start)).collect(Collectors.joining("."));
        }
        
        /**
         * 获取节点路径的编码：路径编码从1开始
         * @return 节点路径的编号
         */
        public String getPathCode() {
            return getPathCode(1);
        }

        /**
         * 获得父节点路径
         * 如果父节点为null返回空
         * @return 获取父节点的路径
         */
        public String getParentPath() {
            if(this.getParent()==null)return null;
            return this.getParent().getPath();
        }
        
        /**
         * 获取父节点 节点路径
         * @return 节点路径
         */
        public Stream<Node<T>> getParentPathNodes(){
            return Node.getPathNodes(this.getParent());
        }

        /**
         * 获取节点路径
         * @param node 节点
         * @return 节点路径
         */
        public String getPath(final Node<T> node) {
            return this.getPath(node,null);
        }
        
        /**
         * 获取节点路径
         * @param node 节点
         * @param name_mapper 节点名称变换器 : node->String
         * @return 节点路径
         */
        public String getPath(final Node<T> node,final Function<Node<T>,String> name_mapper) {
            if(node==null)return "";
            final Function<Node<T>,String> final_name_mapper = name_mapper==null? Node::getName :name_mapper;
            String ppath = this.getPath(node.getParent(),final_name_mapper);
            if(!ppath.matches("[\\s]*"))ppath+="/";
            return ppath+final_name_mapper.apply(node);
        }
        
        /**
         * 获取节点路径
         * @param <X>节点的值的类型
         * @param node 节点对象
         * @return 节点路径
         */
        public static <X> Stream<Node<X>> getPathNodes(final Node<X> node){
            if(node==null)return Stream.of();
            else return Stream.concat(Node.getPathNodes(node.getParent()),Stream.of(node));
        }

        /**
         * 这是专门为IRecord 设计的一个提取键值的简单的办法
         * String key record 的键值名
         */
        public Object recget(String key) {
            if(this.value !=null && this.value instanceof IRecord) {
                IRecord rec = (IRecord)this.value;
                return rec.get(key);
            }
            return null;
        }

        /**
         * 这是专门为IRecord 设计的一个提取键值的简单的办法
         * String key record 的键值名
         */
        public String recstr(String key) {
            if(this.value !=null && this.value instanceof IRecord) {
                IRecord rec = (IRecord)this.value;
                return rec.str(key);
            }
            return null;
        }

        /**
         * 这是专门为IRecord 设计的一个提取键值的简单的办法
         * String key record 的键值名
         */
        public Number recnum(String key) {
            if(this.value !=null && this.value instanceof IRecord) {
                IRecord rec = (IRecord)this.value;
                return rec.num(key);
            }
            return null;
        }

        /**
         * 这是专门为IRecord 设计的一个提取键值的简单的办法
         * String key record 的键值名
         */
        public Integer reci4(String key) {
            if(this.value !=null && this.value instanceof IRecord) {
                IRecord rec = (IRecord)this.value;
                return rec.i4(key);
            }
            return null;
        }

        /**
         * 这是专门为IRecord 设计的一个提取键值的简单的办法
         * String key record 的键值名
         */
        public Double recdbl(String key) {
            if(this.value !=null && this.value instanceof IRecord) {
                IRecord rec = (IRecord)this.value;
                return rec.dbl(key);
            }
            return null;
        }

        /**
         * 这是专门为IRecord 设计的一个提取键值的简单的办法
         * String key record 的键值名
         */
        public Timestamp rectimestamp(String key) {
            if(this.value !=null && this.value instanceof IRecord) {
                IRecord rec = (IRecord)this.value;
                return rec.timestamp(key);
            }
            return null;
        }

        /**
         * 这是专门为IRecord 设计的一个提取键值的简单的办法
         * String key record 的键值名
         */
        public Date recdate(String key) {
            if(this.value !=null && this.value instanceof IRecord) {
                IRecord rec = (IRecord)this.value;
                return rec.date(key);
            }
            return null;
        }
        
        /**
         * 获取节点相对于父节点的子节点索引号<br>
         * 索引序号从0开始,根节点的Index 序号为0
         * @return 节点的索引号
         */
        public int getIndex() {
            if(this.isRoot())return 0;
            final var parent = this.getParent();
            return parent.getChildIndex(this);
        }

        /**
         * 获取所有的子节点信息记录
         * @return 所有子节点包括空节点
         */
        public List<Node<T>> getChildren() {
            return children;
        }
        
        /**
         * 提取满足条件的节点
         * @param predicate 节点条件过滤器
         * @return 满足predicate 过滤条件的节点
         */
        public List<Node<T>> getChildren(Predicate<Node<T>>predicate) {
            return children.stream().filter(predicate).collect(Collectors.toList());
        }
        
        /**
         * 获取子节点的索引序号
         * @param cmp 节点的比较器
         * @return 获取子节点的索引序号 从开始,查询不到返回 -1
         */
        public Integer getChildIndex(final Predicate<Node<T>>cmp) {
            for(int i = 0;i<this.size();i++) {
                if(cmp.test(this.getChild(i)))return i;
            }
            return -1;
        }
        
        /**
         * 获取子节点的索引序号
         * @param node 子节点 对象
         * @return 获取子节点的索引序号 从0开始
         */
        public Integer getChildIndex(final Node<T> node) {
            return this.getChildIndex(n->n==node);
        }
        
        /**
         * 提取第i个索引位置的节点
         * @param i 子节点索引 从0开始,当节点索引i超过节点数量（包含）时候，返回null
         * @return 第i个子节点
         */
        public Node<T> getChild(int i) {
            return children.size()>i?children.get(i):null;
        }
        
        /**
         * 添加子节点,自动设置子节点的父节点,做检测c的存在性检测
         * @param c 子节点,null 节点不添加
         */
        public void addChild(Node<T> c) {
            this.addChild(c, false,true);
        }

        /**
         * 添加子节点,自动设置子节点的父节点
         * @param c 子节点
         * @param b 是否添加空节点,true 添加空节点,false 空节点不添加
         * @param checkExists 是否做子节点的存在性检测  true 检测(同一节点可以添加多次),false 不检测
         */
        public void addChild( final Node<T> c, final boolean b,final boolean checkExists) {
            if(c!=null) {
                if(checkExists && this.hasChild(c)) {// 存在性检测
                    //System.out.println("节点"+c+",已存在");
                    return;
                }//if 存在性检测
                this.children.add(c);
                c.setParent(this);
            }else {
                if(b)this.children.add(null);
            }
        }

        /**
         * 是否包含由孩子节点
         * @param c 孩子节点
         * @return 是否含有指定的节点数据
         */
        public boolean hasChild(Node<T> c) {
            return this.getChildren().contains(c);
        }

        /**
         * 是否包含由孩子节点
         * @param cc 孩子节点列表
         * @return
         */
        public boolean hasChildren(List<Node<T>> cc) {
            return (Integer) cc.stream().mapToInt(e -> this.hasChild(e) ? 1 : 0).sum() == cc.size();
        }

        /**
         * 添加子节点
         * @param cc 子节点集合
         */
        void addChildren(List<Node<T>>cc){
            this.children.addAll(cc);
            cc.forEach(c->c.setParent(this));//设置父节点
        }

        /**
         * 注意这里是通过addChildren 完成父子关系的构建。设置父节点
         * 并不保证父节点的子节点中包含有 本节点(this)。所以可以 setParent(null)
         * 这样就在逻辑上构建了一个独立的树（根节点没有父节点，每颗树只有一个父节点）
         *
         * 设置父节点:不会为parent添加this作为子节点
         * @param parent 父节点对象，可以为null,这样就是表明他是一颗树的根
         */
        public void setParent(Node<T> parent){
            this.parent=parent;
        }
        
        /**
         * 把 设置i个孩子节点为p节点，如果p为非空会自动将 p的父节点设置为 this
         * @param i 子节点索引号,从0开始,i 索引号需要小于 子节点的长度。
         * @param p 待设置的节点
         */
        public void setChild(final int i,Node<T> p) {
            var n = this.size();
            if(i<n) {
                this.children.set(i, p);// 设置孩子节点
                if(p!=null)p.setParent(this);// 设置父亲节点
            }//if
        };
        
        /**
         * 没有子节点或是子节点为null的节点的高度为1<br>
         * 返回节点的高度 ，没有孩子的节点高度为1,否个节点的高度为最高的孩子节点的高度+1
         * @return 节点的高度，从1开始。
         */
        public int height() {
            final var children = this.getChildren(Objects::nonNull);
            if(children.size()==0)return 1;
            return children.parallelStream().map(Node::height).collect(Collectors.summarizingInt(e->e)).getMax()+1;
        }

        /**
         * 判断当前节点是否为根节点
         *
         * @return
         */
        public boolean isRoot() {
            return this.getParent() ==null;
        }

        /**
         * 是否是叶子节点
         * @return 是否为叶子节点
         */
        public boolean isLeaf() {
            return this.children.size()<=0;
        }

        /**
         * 获取节点所在的层级(空节点层级为0)
         * @return 节点的层级,根节点为1层,根节点的子节点层级为2,以此类推, 即 子节点的层级为父节点的层级+1
         */
        public Integer getLevel() {
            return this.getLevel(this);
        }

        /**
         * 获取指定节点所在的层级(空节点层级为0)
         * 节点的层级,根节点为1层,根节点的子节点层级为2,以此类推, 即 子节点的层级为父节点的层级+1
         * @param node 节点数据
         * @return 节点的层级,根节点为1层,根节点的子节点层级为2,以此类推, 即 子节点的层级为父节点的层级+1
         */
        public Integer getLevel(final Node<T> node) {
            if(node==null)return 0;
            return this.getLevel(node.getParent())+1;
        }

        /**
         * 获取属性值
         * @param name 属性名称
         * @return 属性值
         */
        public Object prop(String name) {
            return properties.get(name);
        }
        
        /**
         * 获取属性值
         * @param name 属性名称
         * @param mapper 属性变换函数  u->v 把name 视为 属性名称 对其进行变换。
         * @return V 类型的值。
         */
        @SuppressWarnings("unchecked")
        public <U,V> V prop( final String name, final Function<U,V> mapper) {
            return mapper.apply((U)properties.get(name));
        }
        
        /**
         * 提取属性集合，只读 设置为无效。
         * @return IRecord 属性集合
         */
        public IRecord attributes() {
            return REC(this.properties);
        }
        
        /**
         * 提取属性值并制定属性值的类型，只读 设置为无效。
         * @param <U> 返回的结果类型
         * @param name 属性名称
         * @param targetClass 返回结果的类型类
         * @return U 类型的属性值
         */
        @SuppressWarnings("unchecked")
        public <U> U attr(final String name, final Class<U> targetClass) {
            return this.attributes().get(name,targetClass==null? (Class<U>)Object.class:targetClass);
        }
        
        /**
         * 设置属性值
         * @param name 属性名称
         * @param value 属性值
         * @return
         */
        public Object prop(String name,Object value) {
            return properties.put(name,value);
        }

        /**
         * 获取属性集合
         * @return
         */
        public Map<String,Object> props() {
            return properties;
        }

        /**
         * 字符串属性
         * @param name 属性名
         * @return
         */
        public String strProp(String name) {
            Object obj = this.prop(name);
            return obj==null?null:obj+"";
        }

        /**
         * 数字属性属性
         * @param name 属性名
         * @return
         */
        public Number numProp(String name) {
            Object obj = this.prop(name);
            if(obj==null)return null;
            if(obj instanceof Number) return (Number)obj;
            try {obj = Double.parseDouble(obj+"");}catch(Exception e) {e.printStackTrace();};
            return (Number)obj;
        }

        /**
         * 数字属性属性
         * @param name 属性名
         * @return
         */
        public int intProp(String name) {
            return numProp(name).intValue();
        }

        /**
         * 数字属性属性
         * @param name 属性名
         * @return
         */
        public double dblProp(String name) {
            return numProp(name).doubleValue();
        }


        public String toString() {
            return value+"";
        }

        /**
         * 使用产品的名字进行节点散列：采用名称name 进行散开列。
         * @return hashCode
         */
        public int hashCode() {
            // 之所以不采用路径的hashcode 的是为了提高效率，hashCode 的效率。
            return this.getName().hashCode();// 根据名称
        }

        /**
         * 依据名称来进行判断对象属性
         * @param obj 比较对象
         */
        public boolean equals(final Object obj) {
            if(this.hashCode()!=obj.hashCode())return false;
            if (obj instanceof Node) {// 类型相互一致才进行比较
                @SuppressWarnings("unchecked")
                final Node<T> node = (Node<T>) obj;
                final var p0= this.getParent();
                final var p1 = node.getParent();
                if(p0==null && p1!=null) return false;
                else if ( p0==p1 || p0.equals(p1)) {// 先对父级路径进行比较
                    final var v0 = this.getValue();
                    final var v1 = node.getValue();
                    if (v0 == v1)
                        return true;
                    else return v0 != null && v0.equals(v1);
                } else {
                    return false;
                } // if
            } else {
                return false;
            }
        }

        /**
         * 根据路径获取子节点,路径采用"/"进行分割
         * 对于路径 A/B/C, 以节点 A为例 nodeA.path("B/C") 返回节点C
         * @param path
         * @return
         */
        public Node<T> get(Node<T> node,String path){
            if(node==null)return null;
            int p = path.indexOf("/");//产品路径 backslash 位置 pos
            final String name= p<0?path:path.substring(0,p);// 获取一级目录项目
            final String rest = p<path.length()?path.substring(p+1):null;
            if(name.equals(node.getName()))
                return node;
            else {
                Optional<Node<T>> c = node.children.stream().filter(e->e.getName().equals(name)).findFirst();
                if(c.isPresent() && rest!=null) return get(c.get(),rest);//从子节点重继续寻找
            }

            return null;
        }

        /**
         * 路径节点
         */
        public Node<T> get(String path){
            return get(this,path);
        }

        /**
         * 节点遍历
         * @param cs 节点长处理函数
         * @param node 遍历的节点起始节点
         */
        public static <U> void forEach(Consumer<Node<U>> cs,Node<U> node) {
            if(node==null || cs == null)return;
            cs.accept(node);
            for(Node<U> u:node.getChildren())forEach(cs,u);
        }

        /**
         * 以该节点为起始节点，进行树形结构遍历
         * @param cs 节点长处理函数
         */
        public void forEach(Consumer<Node<T>> cs) {
            forEach(cs,this);
        }

        /**
         * 返回所有的 叶子节点
         * @return 叶子节点
         */
        public List<Node<T>> getAllLeaves(){
            return this.flatMap().stream().filter(Node::isLeaf).collect(Collectors.toList());
        }

        /**
         * 树形结构的节点。扁平化成序列列表
         * 以该节点为起始节点，进行树形结构遍历
         *
         * 示例： MAP(root.flatMap(),f->f.val(g->g.str("name")));// 生成一个树形结构的额各个节点名称序列。
         * 这里是一个Node<IRecord> 结构，并且IRecord中包含了name字段
         */
        public synchronized List<Node<T>> flatMap() {
            return this.flatMap(e->e);
        }

        /**
         * 以该节点为起始节点，进行树形结构遍历
         * @param mapper 节点的处理函数 把 <T> 类型转换成 <U> 类型。
         */
        public synchronized <U> List<U> flatMap(Function<Node<T>,U> mapper) {
            if(mapper==null)return null;
            List<U> list = new LinkedList<>();
            this.forEach(e-> list.add(mapper.apply(e)));
            return list;
        }

        /**
         * 树形结构的节点。扁平化成序列列表
         * 以该节点为起始节点，进行树形结构遍历
         *
         * 示例： MAP(root.flatMap(),f->f.val(g->g.str("name")));// 生成一个树形结构的额各个节点名称序列。
         * 这里是一个Node<IRecord> 结构，并且IRecord中包含了name字段
         */
        public synchronized Stream<Node<T>> flatStream() {
            return this.flatStream(e->e);
        }

        /**
         * 以该节点为起始节点，进行树形结构遍历
         * @param mapper 节点的处理函数 把 <T> 类型转换成 <U> 类型。
         */
        public synchronized <U> Stream<U> flatStream(Function<Node<T>,U> mapper) {
            return this.flatMap(mapper).stream();
        }
        
        /**
         * 直接子节点数目:非空节点的数目
         * @return 返回直接子节点数目
         */
        public int size() {
            return this.size(true);
        }
        
        /**
         * 直接子节点数目
         * @param b 是否包含空节点:true 包含,false 不包含
         * @return 返回直接子节点数目
         */
        public int size(boolean b) {
            return b 
            ? this.getChildren().size()
            : this.getChildren(Objects::nonNull).size();
        }

        private T value;// 节点的信息值
        private Node<T> parent=null;// 父节点，初始化为null,表示他是一个根节点，没有父节点
        private Function<Node<T>,String> lambda_name = null;// 获得节点的名称
        private List<Node<T>> children=new LinkedList<>();// 子节点：集合

        private Map<String,Object> properties = new LinkedHashMap<>();// 属性记录的存储空间
    }

    /**
     *   Json 的帮助类
     * @author gbench
     *
     */
    public static class Json {
        
        /**
         * 把一个对象转换成json对象
         * 
         * @param obj 对象
         * @return json 结构的对象
         */
        public static String obj2json(final Object obj) {
            if(obj==null)return "{}";
            String jsn = ""; // jsn 结构的对象
            try {
                Object o = obj;// 对象结构
                //if(o instanceof IRecord) o = ((IRecord)o).toEscapedMap();// 映射对象
                jsn = objM.writeValueAsString(o);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }//try

            return jsn;
        }

        /**
         * 把一个对象转换成json对象 当cls为Map.class 时候结果不会返回null,空值使用一个长度为0的HashMap代替
         * 
         * @param <T> 结果类型
         * @param jsn 对象 json的字符串表示结构，之所以使用Object是便于从Map这样的容器中取值进行直接传送。
         * @return json 结构的对象
         */
        public static<T> IRecord json2rec(final Object jsn) {
            @SuppressWarnings("unchecked")
            final Map<String,Object> map = json2obj(jsn,Map.class,true);
            return new LinkedRecord(map);
        }

        /**
         * 把一个对象转换成json对象 当cls为Map.class 时候结果不会返回null,空值使用一个长度为0的HashMap代替
         * 
         * @param <T> 结果类型
         * @param jsn 对象 json的字符串表示结构，之所以使用Object是便于从Map这样的容器中取值进行直接传送。
         * @param cls 目标类型类型
         * @return json 结构的对象
         */
        public static<T> T json2obj(final Object jsn,final Class<T> cls) {
            return json2obj(jsn,cls,true);
        }

        /**
         * 把一个对象转换成json对象 当cls为Map.class 时候结果不会返回null,空值使用一个长度为0的HashMap代替
         * 
         * @param <T> 结果类型
         * @param jsn 对象 json的字符串表示结构，之所以使用Object是便于从Map这样的容器中取值进行直接传送。
         * @param cls 对象类型
         * @param b   是否打印异常信息
         * @return json 结构的对象
         */
        @SuppressWarnings("unchecked")
        public static<T> T json2obj(final Object jsn,final Class<T> cls, final Boolean b) {

            ObjectMapper objM = new ObjectMapper();
            T obj = null;
            try {
                obj = objM.readValue(jsn + "", cls);
            } catch (Exception e) {
                if (b) e.printStackTrace();
                if (Map.class.isAssignableFrom(cls)) {// 保证当cls为Map的时候不会返回空
                    obj = (T) new LinkedHashMap<>();
                }// if
            } // try

            return obj;
        }

        /**
         * 把一个对象转换成json对象 <br>
         * 当cls为Map.class 时候结果不会返回null,空值使用一个长度为0的HashMap代替
         * 
         * @param jsn     对象 json的字符串表示结构，之所以使用Object是便于从Map这样的容器中取值进行直接传送。
         * @param typeRef 类型信息
         * @return json 结构的对象
         */
        public static<T> T json2obj(final Object jsn,TypeReference<T> typeRef) {

            final var objM = new ObjectMapper();
            T obj = null;
            try {
                obj = objM.readValue(jsn+"",typeRef);
            } catch (Exception e) {
                e.printStackTrace();
            }//try

            return obj;
        }

        /**
         * 生成 record 列表 <br>
         * json2recs
         * 
         * @param jsn 一个jsn数组[{key:value,key2:value2,...},{key:value,key2:value2,...},...]
         * @return IRecord 列表
         */
        public static List<IRecord> json2recs(final Object jsn) {
            return Json.json2obj(jsn, new TypeReference<>() {});// 注意这里 不能用 json2list，必须指定List<IRecord>类型
        }

        /**
         * 这个方法不怎么有用。<br>
         * json2list：这里的转化只是一个形式转化，并没有实际调用序列化函数。<br>
         * 
         * @param jsn       一个jsn数组[{key:value,key2:value2,...},{key:value,key2:value2,...},...]
         * @param itemClass 列表项的数据类型
         * @param <T>       返回结果LIST中的元素的类型
         * @return T 类型的List
         */
        public static <T> List<T> json2list(final Object jsn, final Class<T> itemClass) {
            return Json.json2obj(jsn, new TypeReference<>() {});
        }

        /**
         * 读取json的键值属性
         *
         * @param jsn json 数据
         * @param key 键名
         * @param cls 键的值类型
         * @param <T> 返回结果的类型
         * @return T类型的对象
         */
        @SuppressWarnings("unchecked")
        public static<T> T jsnget(String jsn,String key,Class<T> cls) {
            return (T)json2obj(jsn,Map.class).get(key);
        }

        /**
         * 序列转船成一个map <br>
         * 创造一个Record对象,参数分别是：键名1,键值1,键名2,键值2,。。。的序列。
         * 
         * @return SimpleRecord
         */
        public static Map<Object, Object> seq2map(final Object... values) {
            Map<Object, Object> rec = new LinkedHashMap<>();
            for (int i = 0; i < values.length; i += 2) {
                String key = values[i] + "";// 键值名
                Object value = (i + 1) < values.length ? values[i + 1] : null;// 如果最后一位是key则它的value为null
                rec.put(key, value);
            } // for

            return rec;
        }

        /**
         * 创造一个Record对象,参数分别是：键名1,键值1,键名2,键值2,。。。的序列。
         * @param values 键值序列
         * @return SimpleRecord
         */
        public static String build(final Object... values) {
            Map<Object, Object> rec = new LinkedHashMap<>();
            for (int i = 0; i < values.length; i += 2) {
                String key = values[i] + "";// 键值名
                Object value = (i + 1) < values.length ? values[i + 1] : null;// 如果最后一位是key则它的value为null
                rec.put(key, value);
            } // for
            return obj2json(rec);
        }

        /**
         * 判断一个字符串是否是json,字段需要待由双引号
         * 
         * @param line 待检测的对象
         */
        public static boolean isJson(final Object line) {
            return JsonMode.OTHER != getJsonMode(line);
        }
        
        /**
         * 获取一个字符串line的JsonMode
         * @param line 待检测的对象
         * @return JsonMode 
         */
        public static JsonMode getJsonMode(final Object line) {
            final ObjectMapper objM = new ObjectMapper();
            var type = JsonMode.OTHER;
            final var json = line+"";
            try {
                objM.readValue(json, Map.class);
                type = JsonMode.MAP;
            } catch (Exception e) {
                try {
                    objM.readValue(json, List.class);
                    type = JsonMode.LIST;
                } catch (Exception ee) {
                    // do nothing
                } // try
            } // try

            return type;
        }
        
        public enum JsonMode{
            MAP // 键值对儿格式
            ,LIST // 列表类型
            ,OTHER // 其他类型，非json格式结构
            } // Json模式
        public static ObjectMapper objM = new ObjectMapper();// 默认实现的ObjectMapper
    }
    

    /**
     * 基本时间操作函数
     */
    public static class CronTime{
        /**
         * 
         * @param localDate
         * @return
         */
        public static Date ld2dt(LocalDate localDate) {
            if(localDate==null)return null;
            ZoneId zoneId = ZoneId.systemDefault();
            ZonedDateTime zdt = localDate.atStartOfDay(zoneId);
            return Date.from(zdt.toInstant());
        }
        
        /**
         * localDateTime2Date 的别名
         * @param localDateTime,null 返回null
         * @return
         */
        public static Date ldt2dt(LocalDateTime localDateTime) {
            if(localDateTime==null)return null;
            return localDateTime2date(localDateTime);
        }
        /**
         * 
         * @param localDateTime
         * @return
         */
        public static Date localDateTime2date(LocalDateTime localDateTime) {
            if(localDateTime==null)return null;
            ZoneId zoneId = ZoneId.systemDefault();
            ZonedDateTime zdt = localDateTime.atZone(zoneId);
            return Date.from(zdt.toInstant());
        }
        
        /**
         * date2LocalDateTime的别名
         * @param date 时间
         * @return 本地日期时间
         */
        public static LocalDateTime dt2ldt(Date date) {
            if(date==null)return null;
            return date2localDateTime(date);
        }
        
        /**
         * date -> localDate
         * @param date
         * @return
         */
        public static LocalDateTime date2localDateTime(Date date) {
            if(date==null)return null;
            Instant instant = date.toInstant();
            ZoneId zoneId = ZoneId.systemDefault();
            return instant.atZone(zoneId).toLocalDateTime();
        }
        
        /**
         * 日期Date 转 LocalDate
         * @param date
         * @return
         */
        public static LocalDate dt2ld(Date date) {
            if(date==null)return null;
            return date2localDate(date);
        }

        /**
         * date -> localDate
         * @param date
         * @return
         */
        public static LocalDate date2localDate(Date date) {
            if(date==null)return null;
            Instant instant = date.toInstant();
            ZoneId zoneId = ZoneId.systemDefault();
            return instant.atZone(zoneId).toLocalDateTime().toLocalDate();
        }
    
        
        /**
         * 默认为当日日期
         * @param lt 本地实间
         * @return 日期
         */
        public static Date ld2dt(LocalTime lt) {
            return localTime2date(lt);
        }
        
        /**
         * 默认为当日日期
         * @param lt 本地时间
         * @param ld 本地日期,null 表示当日
         * @return 日期
         */
        public static Date ld2dt(LocalTime lt,LocalDate ld) {
            return localTime2date(lt,ld);
        }
        
        /**
         * 默认为当日日期
         * @param lt 本地时间
         * @param dt 日期,null 表示当日
         * @return 日期
         */
        public static Date ld2dt(LocalTime lt,Date dt) {
            return localTime2date(lt,dt2ld(dt));
        }
        
        /**
         * 日期转LocalTime
         * @param lt 本地时间
         * @return LocalTime
         */
        public static Date  lt2dt(LocalTime lt) {
           return localTime2date(lt);
        }
        
        /**
         * 默认为当日日期
         * @param lt 本地时间
         * @return 日期
         */
        public static Date localTime2date(LocalTime lt) {
            return localTime2date(lt,null);
        }
        
        /**
         * 默认为当日日期
         * @param localTime
         * @param ld 补填出的日期,null 表示当日
         * @return 日期
         */
        public static Date localTime2date(LocalTime localTime,LocalDate ld) {
            LocalDate localDate = ld==null?LocalDate.now():ld;
            LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
            ZoneId zone = ZoneId.systemDefault();
            Instant instant = localDateTime.atZone(zone).toInstant();
            Date date = Date.from(instant);
            return date;
        }
        
        /**
         * 日期转LocalTime
         * @param date 日期值
         * @return LocalTime
         */
        public static LocalTime  dt2lt(Date date) {
            if(date==null)return null;
            Instant instant = date.toInstant();
            ZoneId zone = ZoneId.systemDefault();
            LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
            return localDateTime.toLocalTime();
        }
        
        /**
         * 
         * @param date
         * @return
         */
        public static LocalTime date2localTime(Date date) {
            if(date==null)return null;
            Instant instant = date.toInstant();
            ZoneId zone = ZoneId.systemDefault();
            LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
            return localDateTime.toLocalTime();
        }
        
        /**
         * localDateTime now
         * @return localDateTime now
         */
        public static LocalDateTime now() {
            return LocalDateTime.now();
        }
        
        /**
         * localDateTime now
         * @return localDateTime now
         */
        public static LocalDateTime ldtnow() {
            return LocalDateTime.now();
        }
        
        /**
         * localDate now
         * @return localDate now
         */
        public static LocalDate ldnow() {
            return LocalDate.now();
        }
        
        /**
         * Date now
         * @return Date now
         */
        public static Date dtnow() {
            return new Date();
        }
        
        /**
         * LocalTime Now
         * @return LocalTime Now
         */
        public static LocalTime ltnow() {
            return LocalTime.now();
        }
        
        /**
         * date2LocalDateTime的别名
         *
         * @param year
         * @param mon
         * @param day
         * @param hour
         * @param min
         * @param sec
         * @param ns
         * @return
         */
        public static LocalDateTime ldt(int year,int mon,int day,int hour,int min,int sec,int ns) {
            return LocalDateTime.of(year, mon,day, hour, min, sec, ns);
        }
        
        /**
         * date2LocalDateTime的别名
         * @param year
         * @param mon
         * @param day
         * @param hour
         * @param min
         * @param sec
         * @return
         */
        public static LocalDateTime ldt(int year,int mon,int day,int hour,int min,int sec) {
            return CronTime.ldt(year, mon, day, hour, min, sec,0);
        }
        
        /**
         * date2LocalDateTime的别名
         *
         * @param year
         * @param mon
         * @param day
         * @param hour
         * @param min
         * @return
         */
        public static LocalDateTime ldt(int year,int mon,int day,int hour,int min) {
            return CronTime.ldt(year, mon, day, hour, min, 0,0);
        }
        
        /**
         * date2LocalDateTime的别名
         *
         * @param year
         * @param mon
         * @param day
         * @param hour
         * @return
         */
        public static LocalDateTime ldt(int year,int mon,int day,int hour) {
            return CronTime.ldt(year, mon, day, hour, 0, 0,0);
        }
        
        /**
         * date2LocalDateTime的别名
         *
         * @param year
         * @param mon
         * @param day
         * @return
         */
        public static LocalDateTime ldt(int year,int mon,int day) {
            return CronTime.ldt(year, mon, day, 0, 0, 0,0);
        }
        
        /**
         * date2LocalDateTime的别名
         *
         * @param year
         * @param mon
         * @return
         */
        public static LocalDateTime ldt(int year,int mon) {
            return CronTime.ldt(year, mon, 0, 0, 0, 0,0);
        }
        
        /**
         * date2LocalDateTime的别名
         *
         * @param year
         * @return
         */
        public static LocalDateTime ldt(int year) {
            return CronTime.ldt(year, 0, 0, 0, 0, 0,0);
        }
        
        /**
         * 
         * @param year
         * @param month
         * @param dayOfMonth
         * @return
         */
        public static LocalDate ld(int year,int month,int dayOfMonth) {
            return LocalDate.of(year, month, dayOfMonth);
        }
        
        /**
         *  本地日期
         * @param datestr
         * @return
         */
        public static LocalDate ld(String datestr) {
            Date date = date(datestr);
            return dt2ld(date);
        }
        
        /**
         * 
         * @param hour
         * @param minute
         * @param second
         * @param nanoOfSecond
         * @return
         */
        public static LocalTime lt(int hour,int minute,int second,int nanoOfSecond) {
            return LocalTime.of(hour, minute, second, nanoOfSecond);
        }
        
        /**
         * 
         * @param hour
         * @param minute
         * @param second
         * @return
         */
        public static LocalTime lt(int hour,int minute,int second) {
            return LocalTime.of(hour, minute, second);
        }
        
        /**
         * 
         * @param hour
         * @param minute
         * @return
         */
        public static LocalTime lt(int hour,int minute) {
            return LocalTime.of(hour, minute);
        }
        
        /**
         * 
         * @param hour
         * @return
         */
        public static LocalTime lt(int hour) {
            return LocalTime.of(hour, 0);
        }
        
        /**
         * 整型
         * @param s 字符串
         * @return 整长整型
         */
        public static Integer i4(String s) {
            Integer i = null;
            try {
                i = Integer.parseInt(s);
            }catch(Exception e) {
                e.printStackTrace();
            }
            
            return i;
        }
        
        /**
         * 长整型
         * @param s 字符串
         * @return 长整型
         */
        public static Long lng(String s) {
            Long i = null;
            try {
                i = Long.parseLong(s);
            }catch(Exception e) {
                e.printStackTrace();
            }
            
            return i;
        }
        
        /**
         * 
         * @param s
         * @return
         */
        public static Double dbl(String s) {
            Double i = null;
            try {
                i = Double.parseDouble(s);
            }catch(Exception e) {
                e.printStackTrace();
            }
            
            return i;
        }

        /**
         * 本地时间
         * @param datestr
         * @return
         */
        public static LocalTime lt(String datestr) {
            if(datestr==null) return null;
            var p1=Pattern.compile("(\\d+):(\\d+)").matcher(datestr.strip());
            var p2=Pattern.compile("(\\d+):(\\d+):(\\d+)").matcher(datestr.strip());
            var p3=Pattern.compile("(\\d+):(\\d+):(\\d+)\\.(\\d+)").matcher(datestr.strip());
            LocalTime lt = null;
            try {
                if(p3.matches()) {
                    lt = lt(i4(p3.group(1)),i4(p3.group(2)),i4(p3.group(3)),i4(p3.group(4)));
                }else if (p2.matches())  {
                    lt = lt(i4(p2.group(1)),i4(p2.group(2)),i4(p2.group(3)));
                }else if (p1.matches())  {
                    lt = lt(i4(p1.group(1)),i4(p1.group(2)));
                }else {
                    // do nothing
                }
            }catch(Exception e) {
                e.printStackTrace();
            }
            
            return lt;
        }
        
        /**
         * 提取毫秒
         * @param date
         * @return
         */
        public static int MILLISECOND(Date date) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(Calendar.MILLISECOND);
        }

        /**
         * 提取秒数
         * @param date
         * @return
         */
        public static int SECOND(Date date) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(Calendar.SECOND);
        }
        
        /**
         * 提取分钟
         * @param date
         * @return
         */
        public static int MINUTE(Date date) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(Calendar.MINUTE);
        }
        
        /*
         * 提取小时
         *@reutrn  0-23
         */
        public static int HOUR(Date date) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(Calendar.HOUR_OF_DAY);
        }
        
        /**
         * 提取日期
         * @param date
         * @return
         */
        public static int DATEOFYEAR(Date date) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(Calendar.DAY_OF_MONTH);
        }
        
        /**
         * 提取月份
         * @param date
         * @return 月份数值
         */
        public static int MONTH(Date date) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            return calendar.get(Calendar.MONTH);
        }
        
        /**
         * 日期的解析
         * @param datestr
         * @return 日期对象
         */
        public static Date date(String datestr) {
            Date d = null;
            if(datestr == null)return null;
            var s = datestr.strip();
            try {
                if(s.matches("\\d+-\\d+-\\d+")) {
                    d = sdf2.parse(s);
                }else {
                    d = sdf.parse(s);
                }
            }catch(Exception e) {
                //
            }
            
            if(d==null) {
                final var fmts = new String[] {
                    "yy-MM-dd HH:mm:ss.SSS",
                    "yy-MM-dd HH:mm:ss",
                    "yy-MM-dd HH:mm",
                    "yy-MM-dd HH",
                    "yy-MM-dd",
                    "yy-MM",
                    "yy",
                    "yyyy-MM-dd HH:mm:ss.SSS",
                    "yyyy-MM-dd HH:mm:ss",
                    "yyyy-MM-dd HH:mm",
                    "yyyy-MM-dd HH",
                    "yyyy-MM-dd",
                    "yyyy-MM",
                    "yyyy",
                    "yy-MM-ddTHH:mm:ss.SSS",
                    "yy-MM-ddTHH:mm:ss",
                    "yy-MM-ddTHH:mm",
                    "yy-MM-ddTHH",
                    "yyyy-MM-ddTHH:mm:ss.SSS",
                    "yyyy-MM-ddTHH:mm:ss",
                    "yyyy-MM-ddTHH:mm",
                    "yyyy-MM-ddTHH",
                };// fmts
                for(String fmt:fmts) {
                    try{
                        final var sdf = new SimpleDateFormat(fmt);
                        d = sdf.parse(datestr);
                    } catch(Exception e) {
                        //
                    }
                    if(d!=null)return d;
                }//for
            }// d==null
            
            return d;
        }
        
        /**
         * 日期的即使
         * @param datestr
         * @return 本地时间
         */
        public static LocalDateTime ldt(String datestr) {
            return dt2ldt(date(datestr));
        }
        
        /**
         * 日期格式化式样：yyyy-MM-dd HH:mm:ss
         * @param pattern
         * @return
         */
        public static DateTimeFormatter dtf(String pattern) {
            return DateTimeFormatter.ofPattern(pattern);
        }
        
        public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        public static SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
    } // class CronTime 

    
    /**
     * 前缀树节点
     * @author gbench
     *
     * @param <T> 节点名称的类型。
     */
    public static class TrieNode<T>{
        
        /**
         * 前缀树的节点
         * @param name 节点名称
         */
        public TrieNode(final T name){
            this.name = name;
        }
        
        /**
         * 节点
         * @param name 节点的值
         * @param parent 父节点
         */
        public TrieNode(final T name, final TrieNode<T> parent){
            this.name = name;
            this.parent = parent;
        }
        
        /**
         * 节点流
         * @return 节点流
         */
        public Stream<TrieNode<T>> childrenNodes(){
            return this.chidren.entrySet().stream().map(Map.Entry::getValue);
        }

        /**
         * 当前节点是否拥有一个 叫做name的子节点
         * @param name 节点名称。
         * @return 是否有子节点。
         */
        public boolean hasChild(final T name) {
            return this.chidren.containsKey(name);
        }
        
        /**
         * 为当前节点增加一个 叫做name的子节点。如果已经添加 则 直接返回 该name的子节点。
         * @param name 节点名称
         * @return 名称为 name的TrieNode
         */
        public TrieNode<T> addChild(final T name) {
            return chidren.compute(name, (k, v) -> v == null ? new TrieNode<>(k, this) : v);
        }
        
        /**
         * 添加单词 
         * @param word 单词字符序列
         * @return 添加单词
         */
        @SuppressWarnings("unused")
        public TrieNode<T> addWord(final List<T> word){
            if (false) {// 采用非递归方式实现。好处是 可以效率高。
                var p = this;
                for (var t : word)
                    p = p.addChild(t);
                p.attributes.computeIfAbsent("flag", k -> true);// 设置单词标记
                return p;
            } else { // 采用递归方法来实现,好处是 没有引入本地变量，方便并发
                if (word.size() < 1) {// 标记档次
                    this.attributes.computeIfAbsent("flag", k -> true);// 设置单词标记
                    return this;
                } else {
                    return this.addChild(word.get(0))
                        .addWord(word.subList(1, word.size()));
                }
            }// if
        }
        
        /**
         * 添加单词 
         * @param word 单词字符序列
         * @return 添加单词
         */
        public TrieNode<T> addWord(final T[] word){
            return this.addWord(Arrays.asList(word));
        }
        
        /**
         * 去除根节点之后的字符拼接成一条字符路径（字符序列）
         * @return 字符序列路径。
         */
        public String path() {
            return this.getPath().stream().map(e->e+"").collect(Collectors.joining("")).substring(1);
        }
        
        /**
         * 获取路径
         * @return 添加路径
         */
        public List<T> getPath(){
            if(this.parent==null)
                return Collections.singletonList(this.name);
            else {
                final var ll = new LinkedList<>(this.parent.getPath());
                ll.add(this.name);
                return ll;
            }
        }
        
        /**
         * 提取路径中的 trie节点
         * @param tt 路径信息
         * @return trie节点
         */
        public TrieNode<T> getNode(final List<T> tt) {
            if(!tt.get(0).equals(this.name))return null;
            if(tt.size()==1) {
                return  this;
            }else {
                final var tt1 = tt.subList(1, tt.size());
                final var c = this.chidren.get(tt1.get(0));
                return c==null
                ? null
                :c.getNode(tt1);
            }// if
        }
        
        /**
         * 获取给点
         * @param t 字符名称。
         * @return 获取节点
         */
        public TrieNode<T> getNode(final T t) {
            return this.getNode(Collections.singletonList(t));
        }
        
        /**
         * 获取节点名称
         * @return 节点名称
         */
        public T getName() {
            return this.name;
        }

        /**
         * 获取当前节点的阶层号
         * @return 当前的节点的阶层号从1开始。
         */
        public int getLevel() {
            return this.getPath().size();
        }

        /**
         * 是否拥有一个单词标记。
         * @return 是否是一个单词的尾部节点。
         */
        public boolean flag() {
            return this.attributes.bool("flag");
        }

        /**
         * 判断 tt 是否构成一个有效前缀。
         * @param tt 单词序列
         * @return 单圈是否前缀
         */
        public boolean isPrefix(final List<T> tt) {
           final var t = this.getNode(tt);
           return t != null;
        }
        
        /**
         * 判断是否单词序列
         * @param word
         * @return 判断是否单词序列
         */
        public boolean isWord(final List<T> word) {
           final var t = this.getNode(word);
           return t != null && t.flag();
        }
        
        /**
         * 遍历访问
         * @param cs 单词回调函数
         */
        public void forEach(final Consumer<TrieNode<T>> cs) {
            cs.accept(this);
            this.chidren.forEach((t,e)->e.forEach(cs));
        }

        /**
         * 获取节点名称
         * @return 及诶按属性。
         */
        public IRecord attrs() {
            return this.attributes;
        }
        
        /**
         * 设置节点属性
         * @param name 属性名
         * @param value 属性值
         * @return 节点本身 以实现链式编程
         */
        public TrieNode<T> attrs(final String name, final Object value) {
            this.attributes.set(name, value);
            return this;
        }
        
        /**
         * 获取属性值
         * @param name 属性名
         * @return 属性值
         */
        public Object attr(final String name) {
            return this.attributes.get(name);
        }
        
        /**
         * 获取属性值
         * @param <U> 属性值类型
         * @param name 属性名
         * @return 属性值
         */
        public <U> U attr(final String name, final Class<U> tclass) {
            return this.attributes.get(name,tclass);
        }
        
        /**
         * 字符串格式化
         */
        public String toString() {
            return MessageFormat.format("{0}", this.name);
        }
        
        private final T name; // 节点名称
        private TrieNode<T> parent; // 父节点
        private final IRecord attributes = REC(); // 节点属性
        private final Map<T,TrieNode<T>> chidren = new ConcurrentHashMap<>();// 子节点
    }// TrieNode

    /**
     * 这是对一下的数据结构进行实现。<br>
     * LittleTree.buildTree(categories,0,REC2("id","id","pid","pid"));<br>
     * 从List<Tree> 结构生成节点树 <br>
     * 根节点id 默认为 "0"; <br>
     * @param recs 节点集合，节点需要包含由id,pid两个字段
     * @return Node &lt;IRecord&gt; 类型的根节点
     */
    public static Node<IRecord> buildTree(final List<IRecord> recs){
        return buildTree(recs,"0");
    }
    
    /**
     * 这是对一下的数据结构进行实现。<br>
     * LittleTree.buildTree(categories,0,REC2("id","id","pid","pid")); <br>
     * 从List<Tree> 结构生成节点树 <br>
     * 根节点id 默认为 "0"; <br>
     * @param <T> 节点元素的值类型
     * @param <U> 返回结果类型
     * @param recs 节点集合，节点需要包含由id,pid两个字段
     * @return Node &lt;IRecord&gt; 类型的根节点
     */
    public static <T,U  extends Node<T>> U buildTree2( final List<IRecord> recs,final Function<Node<IRecord>,U> node_mapper){
        return buildTree(recs,"0",node_mapper);
    }

    /**
     * 构建一棵树
     * @param <T> 节点元素的值类型
     * @param sup_root 根节点函数 <br>
     * @param get_children 子节点函数 <br>
     * @return 树形结构的根节点： Node &lt;T&gt; 类型的根节点
     */
    public static <T> Node<T> buildTree( final Supplier<Node<T>> sup_root,
        final Function<Node<T>,List<Node<T>>> get_children){
        
        final Node<T> root = sup_root.get();

        final Stack<Node<T>> stack = new Stack<>();
        stack.push(root);// 根节点入栈，随后开始进行子节点遍历

        while(!stack.empty()) {
            Node<T> node = stack.pop();
            List<Node<T>> cc = get_children.apply(node);
            if(cc.size()>0) {
                stack.addAll(cc);
                node.addChildren(cc);
                //System.out.println(node+"：子节点为："+cc);
            }else {
                //System.out.println(node+"：没有子节点");
            }
        }//while

        return root;
    }

    /**
     * 这个应该是 最常用的生成结构 <br>
     *
     * 从List<Tree> 结构生成节点树 <br>
     *
     * @param recs 节点集合，节点需要包含由id,pid两个字段
     * @param rootId 根节点id， 根节点是通过字符串即对象的toString然后trim 的形式进行比较的。
     * @return 树形结构的根节点： Node &lt;IRecord&gt; 类型的根节点
     */
    public static Node<IRecord> buildTree(List<IRecord> recs ,Object rootId){
        return buildTree(recs ,rootId,SimpleRecord.REC2("id","id","pid","pid"));
    }
    
    /**
     * 这个应该是 最常用的生成结构 <br>
     *
     * 从List<Tree> 结构生成节点树 <br>
     *
     * @param <T> 节点元素的值类型
     * @param <U> 返回结果类型
     * @param recs 节点集合，节点需要包含由id,pid两个字段
     * @param rootId 根节点id， 根节点是通过字符串即对象的toString然后trim 的形式进行比较的。
     * @param node_mapper 节点构建器
     * @return 树形结构的根节点： U 类型的根节点
     */
    public static <T,U  extends Node<T>> U buildTree(List<IRecord> recs ,Object rootId,final Function<Node<IRecord>,U> node_mapper){
        return buildTree(recs ,rootId,SimpleRecord.REC2("id","id","pid","pid"),node_mapper);
    }
    
    /**
     * 这个应该是 最常用的生成结构：自动补充根节点 <br>
     *
     * 从List<Tree> 结构生成节点树 <br>
     * 当rootId 在List<IRecord> 中不存在的时候,在地宫创建一个根节点 <br>
     * REC("id",rootId,"name","根节点","pid",null) 添加到recs之中 <br>
     *
     * @param recs 节点集合，节点需要包含由id,pid两个字段
     * @param rootId 根节点id， 根节点是通过字符串即对象的toString然后trim 的形式进行比较的。
     * @return 树形结构的根节点： Node &lt;IRecord&gt; 类型的根节点
     */
    public static Node<IRecord> buildTree2(final List<IRecord> recs ,final Object rootId){
        final var b = recs.stream().anyMatch(e->e.get("id").equals(rootId));
        if(!b)recs.add(REC("id",rootId,"name","根节点","pid",null));
        return buildTree(recs ,rootId,SimpleRecord.REC2("id","id","pid","pid"));
    }
    
    /**
     * 从List<Tree> 结构生成节点树 <br>
     * 使用示例: <br>
     * LittleTree.buildTree(categories,0,REC2("id","id","pid","p_id")); <br>
     *
     * @param recs 节点集合，节点需要包含由id,pid两个字段
     * @param rootId 根节点id， 根节点是通过字符串即对象的toString然后trim 的形式进行比较的。
     * @param mappings 节点id,父节点id 与IRecord集合recs中的属性字段的对应关系
     * @return 树形结构的根节点： Node &lt;IRecord&gt; 类型的根节点
     */
    public static Node<IRecord> buildTree(List<IRecord> recs ,Object rootId,IRecord mappings){
        return buildTree(recs,rootId,mappings.toMap());
    }

    /**
     * 从List<Tree> 结构生成节点树,生成一个U结构的树 <br>
     * 使用示例:
     * LittleTree.buildTree(categories,0,REC2("id","id","pid","p_id")); <br>
     *  
     * @param <T> 节点元素的值类型
     * @param <U> 付汇结果的节点类型
     * @param recs 节点集合，节点需要包含由id,pid两个字段
     * @param rootId 根节点id， 根节点是通过字符串即对象的toString然后trim 的形式进行比较的。
     * @param mappings 节点id,父节点id 与IRecord集合recs中的属性字段的对应关系
     * @param node_mapper 节点构建器
     * @return 树形结构的根节点：U 类型的根节点
     */
    public static <T,U  extends Node<T>> U buildTree(final List<IRecord> recs, final Object rootId, final IRecord mappings,
        final Function<Node<IRecord>,U> node_mapper){
        
        if(node_mapper==null||recs==null||mappings==null||rootId==null)return null;
        final Node<IRecord> root = buildTree(recs,rootId,mappings);
        final Map<String,U> nodeCache = new HashMap<>();
        final U uroot = node_mapper.apply(root);
        nodeCache.put(root.getPath(),uroot );
        root.forEach(e->{
            if(e.getParent()==null)return;
            final U pcategory = nodeCache.get(e.getParentPath());//获得父节点
            final U catnode = node_mapper.apply(e);
            pcategory.addChild(catnode);
            nodeCache.put(e.getPath(), catnode);
        });
        return uroot;
    }

    /**
     * 从List<Tree> 结构生成节点树 <br>
     *
     * @param rootId 根节点id， 根节点是通过字符串即对象的toString然后trim 的形式进行比较的。 
     * @param mappings 节点id,父节点id 与IRecord集合recs中的属性字段的对应关系 
     * @return 树形结构的根节点： Node &ltIRecordT&gt; 类型的根节点
     */
    public static Node<IRecord> buildTree(final List<IRecord> recs , final Object rootId, final Map<String,?> mappings){
        //获得根节点
        final String id =  (mappings.get("id")+"").trim();
        final String pid = (mappings.get("pid")+"").trim();
        Optional<IRecord> optRoot = SimpleRecord.fetchOne(recs,id, rootId);

        if(!optRoot.isPresent())optRoot = SimpleRecord.fetchOne(recs.stream()
            .map(e->e.duplicate().set("id", e.get("id")+""))
            .collect(Collectors.toList()),id, rootId+"");// 转换成字符串类型进行比较

        if(!optRoot.isPresent()) {
            System.out.println("无法确认根节点(不存在根节点：id/"+rootId+")");
            return null;
        }//if

        final IRecord final_root = optRoot.get();
        //获取根节点
        final Supplier<Node<IRecord>> sp_root = ()-> new Node<>(final_root);
        //获得子节点
        final Function<Node<IRecord>,List<Node<IRecord>>> get_children =
            (node)->recs.stream()
                .filter(e->node.recget(id).toString().equals(e.get(pid)))// 父子节点关系
                .map(Node::new)
                .collect(Collectors.toList());
        //创建树结构
        final Node<IRecord> tree = LittleTree.buildTree(sp_root,get_children);
        return tree;
    }

    /**
     * 创建属性结构
     * @param paths, 每条路径采用一维数组进行表示， 路径列表 [a,b,c1],[a,b,c2],....
     * @param node_creator  节点创建函数 （节点名称->节点数据)
     * @return 树形结构的根节点： Node &lt;T&gt; 类型的根节点
     */
    public static <T> Node<T> buildTree(final List<String[]> paths,final Function<String,Node<T>> node_creator){
        
        final Map<String,Node<T>> map = new LinkedHashMap<>();
        final Function<List<String>,String> buildpath = list-> String.join("/", list);
        paths.forEach(ss->{
            final List<String> list = new LinkedList<>();
            for(String s:ss) {
                final String parent = buildpath.apply(list);
                list.add(s);
                final String cur= buildpath.apply(list);
                if(map.get(cur)==null)map.put(cur, node_creator.apply(s));

                final Node<T> pnode = map.get(parent);
                final Node<T> node = map.get(cur);
                if(pnode!=null && !pnode.hasChild(node)) pnode.addChild(node);
            }//for
        });
        
        final Node<T> root = map.values().iterator().next();
        return root;
    }

    /**
     * 遍历树形结构
     * @param root 根节点
     * @param cs 回调函数
     * @param level 阶层数
     */
    protected static <T> void traverse(final Node<T> root,
        final BiConsumer<Node<T>,Integer> cs,final int level) {

        if(root!=null) {
            cs.accept(root,level);
            root.children.forEach(e->traverse(e,cs,level+1));
        }//if
    }

    /**
     * 遍历树形结构
     * @param root 根节点
     * @param cs 回调函数
     * @param level 阶层数
     */
    protected static <T> void traverse_throws(final Node<T> root,
        final BiConsumerThrows<Node<T>,Integer> cs, final int level) throws Exception{
        if(root!=null) {
            if(cs.accept(root,level))for(Node<T>e:root.children)traverse_throws(e,cs,level+1);
        }//if
    }

    /**
     * 遍历树形结构
     * @param root 根节点
     * @param cs 回调函数 返回 false 终止遍历.
     * @throws Throwable
     */
    public static <T,U extends Node<T> > void traverse_throws2(final U root,
        final BiConsumerThrows<U,Integer> cs) throws Exception{
        traverse_throws2(root,cs,0);
    }

    /**
     * 遍历树形结构
     * @param root 根节点
     * @param cs 回调函数
     * @param level 阶层数
     */
    @SuppressWarnings("unchecked")
    protected static <T,U extends Node<T>> void traverse_throws2(final U root,
        final BiConsumerThrows<? super U,Integer> cs,int level) throws Exception{
        
        if(root!=null) {
            BiConsumerThrows<U,Integer> cs1 = (BiConsumerThrows<U,Integer>)cs;
            if(cs.accept(root,level))for(Node<T>e:root.getChildren())traverse_throws2((U)e,cs1,level+1);
        }//if
    }

    /**
     * 遍历树形结构
     * @param <T> 值类型
     * @param <U> 遍历节点类型 Node &lt; T &gt;
     * @param root 根节点
     * @param cs 回调函数 （node,level)->{} node 节点数据,level 层级高度,0开始,即根节点所在层为0，其子节点层号为1,按照子节点是父节点层号+1的规则依次递推。
     */
    @SuppressWarnings("unchecked")
    public static <T,U extends Node<T>> void traverse(final U root, final BiConsumer<U ,Integer> cs) {
        traverse((Node<T>)root,(BiConsumer<Node<T>,Integer>)(Object)cs,0);
    }
    
    /**
     * 遍历树形结构:从叶子节点向根节点进行遍历
     * @param <T> 值类型
     * @param <U> 遍历节点类型 Node &lt; T &gt;
     * @param node 根节点
     * @param cs 回调函数 （node,level)->{} node 节点数据,level 层级高度,0开始,即根节点所在层为0，其子节点层号为1,按照子节点是父节点层号+1的规则依次递推。
     */
    @SuppressWarnings("unchecked")
    public static <T,U extends Node<T>> void traverse2(final U node, final BiConsumer<U ,Integer> cs) {
        
        if(node.isLeaf()) {
            cs.accept((U)node,node.getLevel());
        }else{
            node.getChildren().forEach(child->traverse2((U)child,cs));
            cs.accept((U)node,node.getLevel());
        }//if
    }

    /**
     *
     * @author gbench
     * accept 返回 false终止遍历
     * @param <T> 输入参数1类型 用在 traverse_throws T类型就是节点类型
     * @param <U> 输入参数2的类型 用在 traverse_throws U类型就是当前节点所在阶层的数值的累心那个
     */
    public interface BiConsumerThrows<T,U>{
        boolean accept(T t, U u)throws Exception;
    }

    /**
     * 遍历树形结构
     * @param root 根节点
     * @param cs 回调函数 返回 false 终止遍历.
     * @throws Throwable
     */
    public static <T> void traverse_throws(final Node<T> root, final BiConsumerThrows<Node<T>,Integer> cs) throws Exception{
        traverse_throws(root,cs,0);
    }

    /**
     * 缩进尺度
     * @param n 缩进记录
     * @return 缩进字符串
     */
    public static <T> String ident(final int n) {
        return String.join("", rep("\t", n));
    }
    
    /**
     * 位数精度:fraction的别名
     * @param n 位数的长度
     * @return 小数位置的精度
     */
    public static Function<Object,String> frt(final int n){
        return fraction(n);
    }

    /**
     * 位数精度
     * @param n 位数的长度
     * @return 小数位置的精度
     */
    public static Function<Object,String> fraction(final int n){
        return v->{
            if(v==null) return"(null)";
            var line = "{0}";// 数据格式化
            if(v instanceof Date) {
                line = "{0,Date,yyyy-MM-dd HH:mm:ss}"; // 时间格式化
            }else if(v instanceof Number) {
                line = "{0,number,"+("#."+"#".repeat(n))+"}"; // 数字格式化
            }//if
            return MessageFormat.format(line, v);
        };// cell_formatter
    }

    /**
     * 重n个对象放在列表
     * @param<T> 元素类型
     * @param obj 对象
     * @param n 必须大于0
     * @return T 重复n 次后的序列
     */
    public static <T> List<T> rep(final T obj,final int n) {
        return Stream
            .iterate(0, i->i+1).limit(Math.max(n, 0))
            .map(e->obj)
            .collect(Collectors.toList());
    }

    /**
     * 缩进尺度
     * @param ws 空白:whitespace
     * @param n 缩进记录
     * @return 缩进字符串
     */
    public static String ident(final String ws,final int n) {
        return String.join("", rep(ws, n));
    }

    /**
     * 生成Json的树形解构
     * @param node
     * @return json
     */
    public static String json(final Node<IRecord> node) {
        StringBuffer buffer = new StringBuffer();
        traverse4json(node,0,buffer);
        return buffer.toString();
    }

    /**
     * 生成一个json的树形结构
     * @param node 节点
     */
    public static String traverse4json(final Node<IRecord> node) {
        StringBuffer buffer = new StringBuffer();// 构建一个局部变量用户递归遍历
        traverse4json(node,0,buffer);
        return buffer.toString();
    }

    /**
     * 为了json而缓存
     * @param node 节点
     * @param level 层级
     * @param buffer 遍历缓存
     */
    private static StringBuffer traverse4json(final Node<IRecord> node,final int level, final StringBuffer buffer) {

        Function<IRecord,String> rec2jsn = (rec)-> rec.stream()
                .map(e->"\""+e.key()+"\":\""+e.value()+"\"")
                .collect(Collectors.joining(","));

        // 打印jsn
        buffer.append(ident(level)).append("{").append(rec2jsn.apply(node.getValue()));

        // 非叶子节点
        if(!node.isLeaf()) {
            buffer.append(",children:[\n");
            node.getChildren().forEach(e->traverse4json(e,level+1,buffer));
        }

        boolean b = false;//是否是子节点中的最后一个
        if(node.getParent()!=null) {
            List<Node<IRecord>> cc = node.getParent().getChildren();
            if(cc.size()>0) {
                if(node.equals(cc.get(cc.size()-1)))b=true;
            }
        }

        // 收尾节点
        buffer.append(ident(level)).append(node.isLeaf() ? "" : "]").append("}").append(node.isRoot() ? "" : (b ? "" : ",")).append("\n");

        return buffer;
    }
    
    /**
     * 强制类型转换 Force Cast
     * @param <T> 元数据类型
     * @param <U> 目标类型
     * @return 一个强制类型转换的函数。T -> U 类型的函数
     */
    @SuppressWarnings("unchecked")
    public static <T,U> Function<T,U> FC(final Class<U> u){
        return o->(U)o;
    }
    
    /**
     * 字符串解析:
     * "1:10",解析成 1,2,3,4,5,6,7,8,9
     * 1 inclusive, 10 exclusive
     * @param line
     * @return 数组序列。
     */
    public static Integer[] NN( final String line) {
        return NATS(line).toArray(new Integer[0]);
    }
    
    /**
     * 字符串序列解析(函数):
     * "1:10",解析成 1,2,3,4,5,6,7,8,9
     * 1 inclusive, 10 exclusive
     * @param line
     * @return 数组序列。
     */
    public static Function<String,Integer[]> series= LittleTree::NN;
    
    /**
     * 字符串解析:
     * "1:10",解析成 1,2,3,4,5,6,7,8,9
     * 1 inclusive, 10 exclusive
     * @param line
     * @return 数组序列。
     */
    public static List<Integer> NATS( final String line) {
        final var ll = new LinkedList<Integer>();
        final var matcher = Pattern.compile("\\s*([0-9-]+)\\s*:\\s*([0-9-]+)\\s*(:\\s*([0-9-]+))?\\s*").matcher(line);
        
        if(matcher.matches()) {
            try {
                final var n = matcher.groupCount();
                final var start = Integer.parseInt(matcher.group(1));
                final var end = Integer.parseInt(matcher.group(2));
                final var sign = end >=start ? 1:-1;
                var step = sign;// 步长
                final var s_step = matcher.group(4);
                if(n>2 && s_step!=null) step = sign*Math.abs(Integer.parseInt(s_step));
                for(var i=start;(sign>0?i<end:i>end);i+=step)ll.add(i);
            }catch(Exception e) {
                e.printStackTrace();
            }// try
        }// if
        
        return ll;
    }

    /**
     * 自然数子集合．0,1,2,3,....
     * 生成一个特定长度的字数字流,从０开始
     * @param size 流的长度,n 为null 或者0,负数返回无限流.
     * @return 序列长度
     */
    public static Stream<Long> NATS(final Integer size){
        if(size==null||size<=0)NATS();
         return Stream.iterate(0L, (Long i)->i+ 1L).limit(size);
     }

    /**
     * 自然数子集合．0,1,2,3,....
     * 生成一个无限长度的数字流.0,1,2,3,....
     * @return 数字序列
     */
    public static  Stream<Long> NATS(){
         return Stream.iterate(0L, (Long i)->i+ 1L);
    }

    /**
     * double 随机数 : DouBLs
     * @param n 随机数的superior 上限
     * @return 浮点数的数字
     */
    public static Double[] DBLS(final int n) {
        return NATS(n).map(e->new Random().nextDouble()).toArray(Double[]::new);
    }

    /**
     * double 随机数 : DouBLs
     * @param n 随机数的superior 上限
     * @return 浮点数的数字
     */
    public static double[] dbls(final int n) {
        return NATS(n).map(e->new Random().nextDouble()).mapToDouble(e->e).toArray();
    }

    /**
     * double 随机数 :DouBLs Stream
     * @param n 随机数的superior 上限
     * @return 浮点数的数字的流
     */
    public static Stream<Double> DBLSTREAM(final int n) {
        return NATS(n).map(e->new Random().nextDouble());
    }

    /**
     * double 随机数 
     * @param n 随机数的superior
     * @param nfractions 小数的位数
     * @return
     */
    public  static Double RNDDBL(final int n,final int nfractions) {
        
        final Number  d = Math.random()*n;
        StringBuilder f= new StringBuilder("#.");
        for(var i=0;i<nfractions;i++) f.append("0");
        var df = new DecimalFormat(f.toString());
        String s = df.format(d);
        //System.out.println(s);
        return Double.parseDouble(s);
    }

    /**
     * int 随机数
     * 
     * @param n 随机数的superior
     * @return 随机整数
     */
    public static int RNDINT(final int n) {
        return new Random().nextInt(n);
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些 <br>
     * LIST的医用用途就是去克隆列表。比如： <br>
     * ------------------------------- <br>
     * var a = asList(0,1,2,3,4,5,6,7); <br>
     * var b = LIST(a.subList(1, 4)); <br>
     * b.addAll(asList(9,10,11)); <br>
     * 
     * a:[0, 1, 2, 3, 4, 5, 6, 7] <br>
     * b:[1, 2, 3, 9, 10, 11] <br>
     * -------------------------------- <br>
     * 对比： <br>
     * var a = new LinkedList<Integer>();// 使用链表方便进行拆解。 <br>
     * a.addAll(asList(0,1,2,3,4,5,6,7)); <br>
     * var b = a.subList(1, 4);// 返回的是一个视图 <br>
     * b.addAll(asList(9,10,11)); <br>
     * 
     * a:[0, 1, 2, 3, 9, 10, 11, 4, 5, 6, 7] <br>
     * b:[1, 2, 3, 9, 10, 11] <br>
     * 
     * @param <T> 元素类型
     * @param coll 流对象
     * @return coll元素组成的列表，注意这是一个coll对象浅层克隆的版本。
     * @return T类型的列表
     */
    public static <T> List<T> LIST( final Collection<T> coll){
        if(coll==null)return null;
        return LIST(coll.stream());
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * @param <T> 元素类型
     * @param tt 流对象
     * @return T类型的列表
     */
    public static <T> List<T> LIST( final T[] tt){
        if(tt==null)return null;
        return LIST(Arrays.stream(tt));
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * 
     * @param <T> 元素类型
     * @param stream 流对象
     * @return T类型的列表
     */
    public static <T> List<T> LIST( final Stream<T> stream){
        if(stream==null)return null;
        return stream.collect(Collectors.toList());
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * @param <T> mapper 定义域
     * @param <U> mapper 值域
     * @param stream 流对象
     * @param mapper 转换器
     * @return  T类型的列表
     */
    public static <T,U> List<U> MAP(final Stream<T> stream, final Function<T,U> mapper){
        if(stream==null)return null;
        return stream.map(mapper).collect(Collectors.toList());
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些<br>
     * 把一个T类型的List转换成一个U类型的 List<br>
     * 
     * @param <T> mapper 定义域
     * @param <U> mapper 值域
     * @param coll T类型的集合对象
     * @param mapper 转换器
     * @return U类型的列表
     */
    public static <T,U> List<U> MAP(final Collection<T> coll, final Function<T,U> mapper){
        if(coll==null)return null;
        return MAP(coll.stream(),mapper);
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * 把一个T类型的List转换成一个R类型对象
     * 
     * @param <T> collector 元数据类型
     * @param <A> collector 累加器类型
     * @param <R> collector 规约值类型
     * @param coll 集合对象
     * @param collector 转换器
     * @return R的规约值类型
     */
    public static <T,A,R> R COLLECT(final Collection<T> coll, final Collector<? super T, A, R> collector){
        if(coll==null)return null;
        return coll.stream().collect(collector);
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些 <br>
     * 把一个T类型的List转换成一个R类型对象 <br>
     * @param <T> collector 元数据类型
     * @param <A> collector 累加器类型
     * @param <R> collector 规约值类型
     * @param stream T类型的流对象
     * @return R的规约值类型
     */
    public static <T,A,R> R COLLECT(final Stream<T> stream, final Collector<? super T, A, R> collector){
        if(stream==null)return null;
        return stream.collect(collector);
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * 把一个T类型的List转换成一个 用逗号进行
     * @param coll 流对象
     * @return 分类征集
     */
    public static  String COMMASTR(final Collection<?> coll){
        if(coll==null)return null;
        return SEQSTR(coll.stream(),",");
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * 把一个T类型的List转换成一个 用逗号进行
     * @param stream 流对象
     * @return 采用逗号“,”进行分割后的字符串对象
     */
    public static String COMMASTR(final Stream<?> stream){
        if(stream==null)return null;
        return SEQSTR(stream,",");
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * 分隔符字符串序列
     * @param coll 流对象
     * @param separator 转换器
     * @return 采用separator进行分割后的字符串对象
     */
    public static  String SEQSTR(final Collection<?> coll, final String separator){
        if(coll==null)return null;
        return SEQSTR(coll.stream(),separator);
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * 分隔符字符串序列
     * @param stream 流对象
     * @param separator 转换器
     * @return 采用separator进行分割后的字符串对象
     */
    public static String SEQSTR(final Stream<?> stream, final String separator){
        if(stream==null)return null;
        return stream.map(Object::toString).collect(Collectors.joining(separator));
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * @param <T> 流的元素类型
     * @param stream T类型流对象
     * @param pfilter 流对象过滤器
     * @return T 类型的列表
     */
    public static <T> List<T> FILTER(final Stream<T> stream, final Predicate<T> pfilter){
        if(stream==null)return null;
        if(pfilter==null) return LIST(stream);
        return stream.filter(pfilter).collect(Collectors.toList());
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * @param <T> 流的元素类型
     * @param <U> 目标流的元素类型
     * @param stream 流对象
     * @param pfilter 流对象过滤器
     * @return U 类型的列表
     */
    public static <T,U> List<U> FILTER(final Stream<T> stream, final Predicate<T> pfilter, final Function<T,U>mapper){
        if(stream==null)return null;
        if(pfilter==null) return MAP(stream,mapper);
        return stream.filter(pfilter).map(mapper).collect(Collectors.toList());
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * 
     * @param <T> 流的元素类型
     * @param coll 集合类
     * @param pfilter 流对象过滤器
     * @return T 类型的列表
     */
    public static <T> List<T> FILTER(final Collection<T> coll, final Predicate<T> pfilter){
        if(coll==null)return null;
        if(pfilter==null) return LIST(coll.stream());
        return coll.stream().filter(pfilter).collect(Collectors.toList());
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * 
     * @param <T> 流的元素类型
     * @param <U> 目标流的元素类型
     * @param coll 集合类
     * @param pfilter 流对象过滤器
     * @return U类型列表
     */
    public static <T,U> List<U> FILTER(final Collection<T> coll, final Predicate<T> pfilter, final Function<T,U>mapper){
        if(coll==null)return null;
        if(pfilter==null) return MAP(coll.stream(),mapper);
        return coll.stream().filter(pfilter).map(mapper).collect(Collectors.toList());
    }

    /**
     * 对集合数据进行分组
     * 
     * @param <T> 流的元素类型
     * @param <K> 键名类型
     * @param coll T类型的数据集合
     * @param classifier 分类器
     * @return 以K为键类型 T的列表为值得 Map结构
     */
    public static <T,K> Map<K,List<T>> GROUPBY(final Collection<T> coll, final Function<T,K> classifier){
        if(coll==null)return new HashMap<>();
        return GROUPBY(coll.stream(),classifier);
    }

    /**
     * 对集合数据进行分组
     * 
     * @param <T> 流的元素类型
     * @param <K> 键名类型
     * @param stream T类型的数据流
     * @param classifier 分类器
     * @return 以K为键类型 T的列表为值得 Map结构
     */
    public static <T,K> Map<K,List<T>> GROUPBY(final Stream<T> stream, final Function<T,K> classifier){
        if(stream==null)return new HashMap<>();
        return stream.collect(Collectors.groupingBy(classifier));
    }

    /**
     * 对集合数据进行分组
     * 
     * @param <T> 流的元素类型
     * @param <K> 键名类型
     * @param coll 集合数据
     * @param classifier 分类器
     * @return 以K为键类型 T的列表为值得 Map结构
     */
    public static <T,K> Map<K,T> GROUP2MAP(final Collection<T> coll, final Function<T,K> classifier){
        return GROUP2MAP(coll.stream(),classifier);
    }

    /**
     *对集合数据进行分组
     *  
     * @param <T> 流的元素类型
     * @param <K> 键名类型
     * @param stream 集合数据
     * @param classifier 分类器
     * @return 以K为键类型 T的列表为值得 Map结构
     */
    public static <T,K> Map<K,T> GROUP2MAP(final Stream<T> stream, final Function<T,K> classifier){
        if(stream==null)return new HashMap<>();
        return (Map<K,T>)stream.collect(Collectors.groupingBy(classifier,Collector.of((Supplier<LinkedList<T>>) LinkedList::new,
                LinkedList::add,(aa,bb)->{aa.addAll(bb);return aa;},LinkedList::getFirst)));
    }

    /**
     * 对集合数据进行分组
     * 
     * @param <T> 流的元素类型
     * @param <K> 键名类型
     * @param coll 集合数据
     * @param classifier 分类器
     * @return 以K为键类型 T的列表为值得 Map结构
     */
    public static <T,K> Map<K,Collection<T>> GROUP(final Collection<T> coll, final Function<T,K> classifier){
        return GROUP(coll.stream(),classifier,e->e);
    }

    /**
     * 对集合数据进行分组
     * 
     * @param <T> 流的元素类型
     * @param <K> 键名类型
     * @param stream 集合数据
     * @param classifier 分类器
     * @return 以K为键类型 T的列表为值得 Map结构
     */
    public static <T,K> Map<K,Collection<T>> GROUP(final Stream<T> stream, final Function<T,K> classifier){
        return GROUP(stream,classifier,e->e);
    }

    /**
     * 对集合数据进行分组
     * @param <T> 流的元素类型
     * @param <K> 键名类型
     * @param <U> 键值列表的元素类型
     * @param coll 集合数据
     * @param classifier 分类器
     * @param finalizer  归并函数
     * @return 以K为键类型 U的列表为值得 Map结构
     */
    public static <T,K,U> Map<K,U> GROUP(final Collection<T> coll, final Function<T,K> classifier, final Function<Collection<T>,U> finalizer){
        return GROUP(coll.stream(),classifier,finalizer);
    }

    /**
     * 对集合数据进行分组
     * 
     * @param <T> 流的元素类型
     * @param <K> 键名类型
     * @param <U> 键值列表的元素类型
     * @param stream T类型的源数据流
     * @param classifier 分类器
     * @return 以K为键类型 U的列表为值得 Map结构
     */
    public static <T,K,U> Map<K,U> GROUP( final Stream<T> stream, final Function<T,K> classifier, final Function<Collection<T>,U> finalizer){
        if(stream==null)return new HashMap<>();
        return (Map<K,U>)stream.collect(Collectors.groupingBy(classifier,Collector.of(LinkedList::new,
                Collection::add,(aa,bb)->{aa.addAll(bb);return aa;},finalizer)));
    }

    /**
     * 检查集合中是否窜在一个元素满足指定条件
     * @param predicator 检查㢝元素是否满足指定的条件判断函数。
     * @return 是否存在的满足predicator 条件的元素
     */
    public static <T> Boolean EXISTS(final Stream<T> stream, final Predicate<T> predicator){
        if(stream==null)return false;
        return stream.anyMatch(predicator);
    }

    /**
     * 检查集合中是否窜在一个元素满足指定条件
     * @param predicator 检查㢝元素是否满足指定的条件判断函数。
     * @return
     */
    public static <T,K> Boolean EXISTS(final Collection<T> coll, final Predicate<T> predicator){
        if(coll==null)return false;
        return coll.stream().anyMatch(predicator);
    }

    /**
     * 检查集合中是否窜在一个元素满足指定条件
     * @param e 集合中的元素
     * @return
     */
    public static <T> Boolean EXISTS2(final Collection<T> coll,T e){
        if(coll==null)return false;
        return coll.stream().anyMatch(g->g.equals(e));
    }

    /**
     * 对集合数据进行  进行 首尾连接
     * @param coll 集合数据
     * @param mapper 分类器
     * @param delimiter  分隔符
     * @return 字符串
     */
    public static <T> String JOIN(final Collection<T> coll, final Function<T,String> mapper, final String delimiter) {
        return JOIN(coll.stream(),mapper,delimiter);
    }

    /**
     * 对集合数据  进行 首尾连接
     * @param tt 集合数据
     * @param delimiter 分类器
     * @return 字符串
     */
    public static <T> String JOIN(final T[] tt, final String delimiter) {
        return JOIN(Arrays.stream(tt),e->e+"",delimiter);
    }

    /**
     * 对集合数据 进行 首尾连接
     * @param tt 集合数据
     * @param delimiter 分类器
     * @return 字符串
     */
    public static <T> String JOIN(final T[] tt, final Function<T,String> mapper, final String delimiter) {
        return JOIN(Arrays.stream(tt),mapper,delimiter);
    }
    
    /**
     * 对集合数据 进行 首尾连接
     * @param coll 集合数据<br>
     * delimiter 分割默认为  "/"
     * @return 字符串
     */
    public static <T> String JOIN(final Collection<T> coll) {
        return JOIN(coll.stream(),e->e+"","/");
    }

    /**
     * 对集合数据 进行 首尾连接
     * @param coll 集合数据
     * @param delimiter  分割符号
     * @return 字符串
     */
    public static <T> String JOIN(final Collection<T> coll, final String delimiter) {
        return JOIN(coll.stream(),e->e+"",delimiter);
    }

    /**
     * 对集合数据  进行 首尾连接
     * @param stream 集合数据
     * @param delimiter  分隔符
     * @return 字符串
     */
    public static <T> String JOIN(final Stream<T> stream,final String delimiter) {
        return JOIN(stream,e->e+"",delimiter);
    }

    /**
     * 对集合数据进行   首尾连接
     * @param stream 集合数据
     * @param mapper 转换器
     * @param delimiter 分隔符
     * @return 字符串
     */
    public static <T> String JOIN(final Stream<T> stream, final Function<T,String> mapper, final String delimiter){
        if(stream==null)return "";
        return stream.map(mapper).collect(Collectors.joining(delimiter));
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些 <br>
     * 求两个集合之间的差. 把 coll2在coll1中存在的元素给予删除 <br>
     * coll1-coll2 <br>
     * @param <T> 数据元素的类型
     * @param coll1 集合类1
     * @param coll2 集合类2
     * @return T类型的列表
     */
    public static <T> List<T> DIFF(final Collection<T> coll1, final Collection<T> coll2){
        return FILTER(coll1,e->!coll2.contains(e));
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * 求两个集合之间的交集
     * 
     * @param <T> 数据元素的类型
     * @param coll1 集合类2
     * @param coll2 集合类2
     * @return T类型的列表
     */
    public static <T> List<T> INTERSECT(final Collection<T> coll1, final Collection<T> coll2){
        return FILTER(coll1, coll2::contains);
    }

    /**
     * 之所以写这个方法就是为了把代码写的精减一些
     * 
     * @param <T> 数据元素的类型
     * @param coll1 集合类1
     * @param coll2 集合类2
     * @return T类型的列表
     */
    public static <T> List<T> UNION(final Collection<T> coll1, final Collection<T> coll2){
        List<T> list = LIST(coll1);
        list.addAll(coll2.stream().filter(e->!coll1.contains(e)).collect(Collectors.toList()));
        return list;
    }

    /**
     * 判断一个集合对象是否为空
     *
     * @param <T> 数据元素的类型
     * @param coll 集合对象，coll 为null 返回为null
     * @return 判断coll 是否为空,如果 coll 为null 返回null
     */
    public static <T> Boolean EMPTY(final Collection<T> coll) {
        if(coll==null)return null;
        return coll.isEmpty();
    }

    /**
     * 左部填充
     * @param coll 集合 not Set
     * @param n 长度
     * @return 左部填充了 指定字符的列表
     */
    public static <T> List<T> LFILL(final Collection<T> coll, final int n) {
        return LFILL(coll,n,null);
    }

    /**
     * 左部填充,填充到n位字长
     * @param coll 集合 not Set
     * @param n 长度
     * @param t 填充数据
     * @return 左部填充了 指定字符的列表
     */
    public static <T> List<T> LFILL(final Collection<T> coll, final int n, final T t) {
        if(coll==null)return null;
        int size = coll.size();
        List<T> list = new LinkedList<>();
        for(int i=0;i<n-size;i++)list.add(t);
        list.addAll(coll);
        return list;
    }

    /**
     * 右部填充
     * @param coll 集合 not Set
     * @param n 长度
     * @return 右部填充了 指定字符的列表
     */
    public static <T> List<T> RFILL(final Collection<T> coll, final int n){
        return RFILL(coll,n,null);
    }

    /**
     * 右部填充
     * @param coll 集合 not Set
     * @param n 长度
     * @param t 填充数据
     * @return 右部填充了 指定字符的列表
     */
    public static <T> List<T> RFILL(final Collection<T> coll, final int n, final T t) {
        if(coll==null)return null;
        int size = coll.size();
        List<T> list = new LinkedList<>(coll);
        for(int i=0;i<n-size;i++)list.add(t);

        return list;
    }

    /**
     * 拉链函数
     * @param names 键名列表,用逗号,'-'分隔,为objs中的元素的进行命名，如果为 null 默认采用数组命名，编号从0开始,1,2,3,递增
     * @param objs 数组对象,把多个数组对象按照 names 给出的字段名顺序拼装成一个字段列表
     * @return 一个合并成功的Record列表
     */
    public static List<IRecord> ZIP(final String names, final Object[]...objs){
        Collection<?>[] oo = (Collection<?>[]) Array.newInstance(Collection.class, objs.length);
        for(int i=0;i<objs.length;i++)oo[i]=Arrays.asList(objs[i]);
        return ZIP(names,oo);
    }

    /**
     * 拉链函数
     * @param names 键名列表,用逗号,'-'分隔,为objs中的元素的进行命名，如果为 null 默认采用数组命名，编号从0开始,1,2,3,递增
     * @param objs 数组对象,把多个数组对象按照 names 给出的字段名顺序拼装成一个字段列表
     * @return 一个合并成功的Record列表
     */
    public static List<IRecord> ZIP(final String names, final Collection<?>...objs){
        if(names==null)return ZIP((String[])null,objs);
        return ZIP(names.split("[,-]+"),objs);
    }

    /**
     * 拉链函数
     * @param names 键名列表,为objs中的元素的进行命名，如果为 null 默认采用数组命名，编号从0开始,1,2,3,递增
     * @param objs 数组对象,把多个数组对象按照 names 给出的字段名顺序拼装成一个字段列表
     * @return 一个合并成功的Record列表
     */
    public static List<IRecord> ZIP(final String[] names, final Collection<?> ... objs){
        Function<Collection<?>,Function<Integer,?>> getter = (coll)->{
            if(coll==null||coll.size()<=0)return x->null;// 空值返回一个空值函数
            Object[] oo = coll.toArray();
            int n = oo.length;
            return x->n>=0?oo[x%n]:oo[0];
        };
        final var final_names = (names ==null) 
                ? Stream.iterate(0,e->e+1).limit(objs.length).map(e->e+"").toArray(String[]::new)
                : names;
        List<Function<Integer,?>> gg= Stream.of(objs).map(getter).collect(Collectors.toList());
        Function<Integer,?> hh = getter.apply(Arrays.asList(final_names));
       
        List<IRecord> ll = new LinkedList<>();
        int n  = Arrays.stream(objs).collect(Collectors.summarizingInt(Collection::size)).getMax();
        for(int i=0;i<n;i++) {
            IRecord rec = new SimpleRecord();
            for(int j=0;j<objs.length;j++)rec.add(hh.apply(j)+"",gg.get(j).apply(i));
            ll.add(rec);
        }//for

        return ll;
    }

    /**
     * 对obj的字符串形式进行转义：
     * @param obj 待转义的数据对象
     * @return obj为null 返回null
     */
    public static String ESCAPE2STR(final Object obj) {
        if(obj==null)return null;
        return (obj+"").replaceAll("'", "").replaceAll("\"", "");
    }

    /**
     * 把一个record 改装成一个 只有 name->value两个字段值的 record列表
     * @param rec 字段值
     * @return IRecord 列表
     */
    public static List<IRecord> REC2KVS(final IRecord rec){
        return MAP(rec.kvs(),kvp->SimpleRecord.REC2("key",kvp.key(),"value",kvp.value()));
    }

    /**
     * 把一个Map结构转换成一个 KVP的 键值对儿 序列。
     * @param map 字段值
     * @return IRecord 结构的 List
     */
    public static List<IRecord> MAP2KVS(final Map<String,?> map){
        return MAP(map.entrySet(),entry->SimpleRecord.REC2("key",entry.getKey(),"value",entry.getValue()));
    }

    /**
     * 过滤掉MAP指定的值
     * @param <K> Map的键名类型
     * @param <V> Map的键值类型
     * @param map 源数据。
     * @param filter 过滤器漆
     * @return {K,V} 结构的Map
     */
    public static <K,V> Map<K,V> FILTER(final Map<K,V> map, final BiPredicate<K, V> filter){
        return FILTER(map,filter,e->e);
    }

    /**
     * 过滤掉MAP指定的值
     * @param <K> Map的键名类型
     * @param <V> Map的键值类型
     * @param <U> mapper的值类型
     * @param map 映射对象 源数据
     * @param filter 过滤函数 (k,v)->true/false
     * @param mapper 值变换函数 :v->u
     * @return {K,U} 结构的Map
     */
    public static <K,V,U> Map<K,U> FILTER(final Map<K,V> map, final BiPredicate<K, V> filter,Function<V,U> mapper){
        final Map<K,U> newMap = new HashMap<>();
        map.forEach((k,v)->{if(filter.test(k, v))newMap.put(k, mapper.apply(v));});
        return newMap;
    }
    
    /**
     * 对于复杂对象stream.distinct 无效，这个我一直灭有找到原因，修改了 equals 和hashcode 也是无效。<br>
     * 为对象创建一个 根据键值进行去重的方法。<br>
     * 使用示例： tt 是一个 含有“名称”项目的记录流 <br>
     * LIST(tt.stream().filter(distinctByKey(e->e.str("名称")))); <br>
     * @param <T> Predicate的参数类型
     * @param keyExtractor 提取对象键值
     * @return T类型谓词判断函数
     */
    public static <T> Predicate<T> DISTINCT_BY_KEY(final Function<? super T, Object> keyExtractor){
        final Map<Object, Boolean> map = new ConcurrentHashMap<>();
        return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
    
    /**
     * 计时函数
     * @param supplier 被计时函数
     * @return 毫秒数
     */
    public static double timeit(final Supplier<?> supplier) {
        final long begTime = System.nanoTime();
        supplier.get();
        final long endTime = System.nanoTime();
        final double duration = (endTime-begTime)/1000000d;
        System.out.println("last for:"+duration+"ms");
        return duration;
    }
    
    /**
     * 计时函数
     * @param command 待执行的命令
     * @return command 执行的运行时间
     */
    public static double timeit(final Runnable command) {
        final long begTime = System.nanoTime();
        command.run();
        final long endTime = System.nanoTime();
        final double duration = (endTime-begTime)/1000000d;
        System.out.println("last for:"+duration+"ms");
        return duration;
    }
    
    /**
     * 测试函数的执行时间： 例如：
     * timeit(p->{ 
     *    final List<List<?>> directions = LIST(iterate(0,i->i<10,i->i+1).map(e->asList(1,0,-1)));// 价格的变动方向 
     *    final var ff = cph(directions);// 生成涨跌列表 
     *    ff.forEach(e->e.compute("total",o->e.reduce(kv2int,0, (a,b)->a+b)));
     * System.out.println(FMT2(ff)); //结果输出 
     * },args,true);
     * 
     * @param <T> cons的参数的类型
     * @param cs 被统计函数
     * @param args 被统计函数 参数
     * @param isnano 是否采用纳秒进行时间统计 true 纳秒 false 毫秒时间单位
     * @return 历时时长 纳秒
     * @return 执行结果
     */
    public static <T> long timeit(final Consumer<T> cs, final T args, final boolean isnano){
        final var ai = new AtomicInteger(0);
        final var th = new Thread(()->{
            while(ai.get()>=0) {
                System.out.println(MFT(". {0} S passed",ai.getAndIncrement()));
                try{ Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
            }// while
        });
        th.start();
        final var start = isnano?System.nanoTime():System.currentTimeMillis();
        cs.accept(args);
        final var end = isnano?System.nanoTime():System.currentTimeMillis();
        final var last = end-start;
        ai.set(-1);// 停止计时器
        System.out.println(MFT("\nlast for:{0} {1}",last,isnano?"ns":"ms"));
        return last;
    };
    
    /**
     * 毫秒的计时统计
     * @param cs 被统计函数
     * @param args 被统计函数 参数
     * @return 历时时长 毫秒
     */
    public static <T> long ms_timeit(final Consumer<T> cs, final T args){
        return timeit(cs,args,false);
    }
    
    /**
     * 把 一个数字 n转换成一个字母表中的数值(术语）
     * 在alphabetics中:ABCDEFGHIJKLMNOPQRSTUVWXYZ
     * 比如:0->A,1-B,25-Z,26-AA 等等
     * @param n 数字
     * @param alphas 字母表
     * @return 生成exel式样的名称
     */
    public static String nomenclature ( final Integer n, final String[] alphas){
        final int model = alphas.length;// 字母表尺寸
        final List<Integer> dd = new LinkedList<>();
        Integer num = n;
        do {
            dd.add(num%model);
            num /= model;// 进入下回一个轮回
        } while( num -- >0 ); // num-- 使得每次都是从A开始，即Z的下一个是AA而不是BA
        // 就是这个简单算法我想了一夜,我就是不知道如何让10位每次都从0开始。
        Collections.reverse(dd);
        return dd.stream()
            .map(e->alphas[e])
            .collect(Collectors.joining(""));
    }
    
    /**
     * 列名称： 从0开始
     * 0->A,1->B;2->C;....,25->Z,26->AA
     * @param n 数字
     * @return 类似于EXCEL的列名称
     */
    public static String excelname(final int n) {
        //字母表
        String alphabetics[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""); 
        return nomenclature(n,alphabetics);
    }
    
    /**
     * 纳秒的计时统计
     * @param <T> cs 的参数类型
     * @param cs 被统计函数
     * @param args 被统计函数 参数
     * @return 历时时长 纳秒
     */
    public static <T> long ns_timeit(final Consumer<T> cs,T args){
        return timeit(cs,args,true);
    }
    
    /**
     * 用法示例:// 修改Database上的注解JdbcConfig的url属性
     * SET_FIELD_OF_ANNOTATION(ANNO(Database.class, JdbcConfig.class), "url","jdbc:neo4j:bolt://localhost/mydb?nossl");
     * 
     * 获得指定对象obj的对应class的注解ana，当对obj为class则直接获取其中的注解ana
     * 注意：ANNO无法获取代理对象上的注解．因为在代理对象的类可能是cglib给予组装出来的类
     * @param <T> 注解的类的类型
     * @param target 目标对象实例，指定对象obj的对应class的注解annotation，当对obj为class则直接获取其中的注解annotation
     * @param annotationClass 目标注解类型
     * @return ana注解的内容
     */
    public static <T extends Annotation> T ANNO(final Object target, final Class<T> annotationClass) {
        Class<?> cls = target instanceof Class<?> ?( Class<?>)target:target.getClass();
        return cls.getAnnotation(annotationClass);
    }
    
    /**
     * 用法示例:// 修改Database上的注解JdbcConfig的url属性
     * SET_FIELD_OF_ANNOTATION(ANNO(Database.class, JdbcConfig.class), "url","jdbc:neo4j:bolt://localhost/mydb?nossl");
     * 修改注解中的字段内容
     * @param <T> 注解类型
     * @param annotation 注解对象实例
     * @param annofld 注解中的字段名称
     * @param annoValue 修正的内容．
     */
    public static <T extends Annotation>  void SET_FIELD_OF_ANNOTATION(final T annotation ,
        final String annofld, final Object annoValue) {
        //注解修改工具,只有value非空才给予修改
        BiConsumer<String,Object> modifer = (fldName,value)->{// 修改计划函数
            try {
                if(annotation==null||value==null)return;//只有value非空才给予修改
                InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);
                //var flds = invocationHandler.getClass().getDeclaredFields();
                //for(var fld:flds) System.out.println(fld.getName()+"/"+fld.getType());// 产看注解类的成员结构
                
                // 获取注解中数据
                final String annotationFieldsName = "memberValues"; // 注解中配置的字段存在于memberValues
                Field fld = invocationHandler.getClass().getDeclaredField(annotationFieldsName);
                fld.setAccessible(true);
                @SuppressWarnings("unchecked")
                Map<String, Object> memberValues = (Map<String, Object>) fld.get(invocationHandler);
                if(value!=null)memberValues.put(fldName, value);
            } catch (Exception e) {
                e.printStackTrace();
            }// try
        };// modifer
        
        // 执行修改计划
        modifer.accept(annofld,annoValue);
    }
    
    /**
     * 随机算子
     * 
     * @param <T> 数据元素
     * @param tt  数据集合
     * @return 从 tt随机选择一个元素
     */
    public static <T> T rnd(final T[] tt) {
        return tt[RNDINT(tt.length)];
    }

    /**
     * 随机算子
     * 
     * @param <T> 数据元素
     * @param tt  数据集合
     * @return 从 tt随机选择一个元素
     */
    public static <T> T rnd(final List<T> tt) {
        return tt.get(RNDINT(tt.size()));
    }

    /**
     * 生成一个对 T类型数字 按照 mode 大小  给予取模 的函数，模值为 T类型
     * 
     * @param <T>  模大小  mode 的 类型 
     * @param mode 模的大小
     * @return 生成一个对 T类型数字 按照 mode 大小  给予取模 的函数，模值为 T类型
     */
    @SuppressWarnings("unchecked")
    public static <T extends Number> Function<T,T> mod(final T mode) {
        return n->(T)(Object)(n.longValue()%mode.longValue());
    }
    
    /**
     * 生成一个对 T类型数字 按照 mode 大小  给予取模 的函数，模值为 Integer类型
     * @param <T>  模大小  mode 的 类型 
     * @param mode 模的大小
     * @return 生成一个对 T类型数字 按照 mode 大小  给予取模 的函数，模值为 Integer类型
     */
    public static <T extends Number> Function<T,Integer> intmod(final T mode) {
        return n->((Number)(n.longValue()%mode.longValue())).intValue();
    }
    
    /**
     * 生成一个对 T类型数字 按照 mode 大小  给予取模 的函数，模值为 Long类型
     * @param <T>  模大小  mode 的 类型 
     * @param mode 模的大小
     * @return 生成一个对 T类型数字 按照 mode 大小  给予取模 的函数，模值为 Long类型
     */
    public static <T extends Number> Function<T,Long> lngmod(final T mode) {
        return n->((Number)(n.longValue()%mode.longValue())).longValue();
    }
    
    /**
     * Message FormaT
     * 数据格式化
     * @param pattern number,date
     * @param arguments 参数列表
     * @return 数据格式化
     */
    public static String MFT(final String pattern, final Object ...arguments) {
        return MessageFormat.format(pattern, arguments);
    }
    
    /**
     * 对MFT的模板字符进行转义
     * @param line 源字符串
     * @return 转义后的字符串
     */
    public static String MFT_ESCAPE(final String line) {
        final var l1 = line.replace("'", "''"); // 转义单引号
        final var l2 = l1.replace("{", "'{'"); // 转义左括号
        return l2;
    }
    
    /**
     * 复制  t n 次
     * @param <T> 元素类型
     * @param n 重复的次数
     * @param t 重复的元素
     * @return T类型的列表
     */
    public static <T> List<T> REPEAT(int n,T t){
        return LIST(NATS(n).map(i->t));
    }
    
    /**
     * REPEAT 的别名的列表类型的返回值
     * @param <T> 元素类型
     * @param n 重复的次数
     * @param t 重复的元素
     * @return T类型的列表
     */
    public static <T> List<T> RPT(int n,T t){
        return REPEAT(n,t);
    }
    
    /**
     * REPEAT 的别名的列表类型的返回值
     * @param <T> 元素类型
     * @param n 重复的次数
     * @param t 重复的元素
     * @return T类型的列表
     */
    public static <T> List<T> RPTL(int n,T t){
        return REPEAT(n,t);
    }
    
    /**
     * REPEAT 的别名  的流类型的返回值
     * @param <T> 元素类型
     * @param n 重复的次数
     * @param t 重复的元素
     * @return T类型的数据流
     */
    public static <T> Stream<T> RPTS(int n,T t){
        return REPEAT(n,t).stream();
    }
    
    /**
     * REPEAT 的别名  的数组类型的返回值<br>
     * 这里有个小技巧：就是RPTA可以一个数组类型转换成二维数组类型：比如<br>
     * var aa = new Integer[] {1,2,3,4};<br>
     * var aaa = RPTA(1,aa);<br>
     * aaa 就是一个以aa为行向量的二维数组。<br>
     * 
     * @param <T> 待复制的元素类型
     * @param n 重复的次数
     * @param t 重复的元素
     * @return T[] T类型的数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] RPTA(final int n,final T t){
        final Class<T> tclass = t==null?(Class<T>)Object.class:(Class<T>)t.getClass();
        return REPEAT(n,t).toArray(a->(T[])Array.newInstance(tclass, a));
    }
    
    /**
     * 生成一个编号元组流, 编号从0开始
     * @param <T> 元组类型
     * @param tt 源数据数组
     * @return 编号元组流
     */
    public static <T> Stream<Tuple2<Long,T>> TUPLES(final List<T> tt){
        return TUPLES(tt.stream());
    }
    
    /**
     * 生成一个编号元组流，编号从0开始
     * @param <T> 元组类型
     * @param tt 源数据数组
     * @return 编号元组流
     */
    @SafeVarargs
    public static <T> Stream<Tuple2<Long,T>> TUPLES(final T ... tt){
        return TUPLES(Arrays.stream(tt));
    }
    
    /**
     * 生成一个编号元组流,编号从0开始
     * @param <T> 元组类型
     * @param tt 源数据流
     * @return 编号元组流
     */
    public static <T> Stream<Tuple2<Long,T>> TUPLES(final Stream<T> tt){
        return TUPLES(tt,null);
    }
    
    /**
     * 生成一个编号元组流
     * @param <T> 元组类型
     * @param tt 源数据流
     * @param start 开始编号,空值 表示从0开始
     * @return 编号元组流
     */
    public static <T> Stream<Tuple2<Long,T>> TUPLES(final Stream<T> tt,final Number start){
        final var al = new AtomicLong(start==null? 0L :start.longValue());
        return tt.map(t-> new Tuple2<>(al.getAndIncrement(), t));
    }
    
    /**
     * 把以数组额元素进行倒转:即尾为前,前转尾
     * @param <T> 数组元素的类型
     * @param tt 数组元素
     * @return T[] 倒转后的数组。
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] reverse(final T[] tt) {
        final var ll = Arrays.asList(tt);
        var tclazz = ll.stream().filter(Objects::nonNull).map(e->(Class<T>)e.getClass()).findAny().orElse(null);
        if(tclazz==null)return tt;
        Collections.reverse(ll);
        return ll.toArray(n->(T[])Array.newInstance(tclazz,n));
    }
    
    /**
     * 包装一个计数器:计数变量从init开始,每次增加 step
     * 这就是模拟for(long i = start;i<end;i+=step) 的语句。
     * 用于对一个stream进行遍历和截取。
     * 
     * @param start 开始数值
     * @param step 步长
     * @param tester 测试函数:(i,t)-> true|false,
     * i 索引从start开始，t 当前的数值。
     * @return
     */
    public static <T> Predicate<T> i_for(long start,long step, final BiPredicate<Long,T> tester){
        final AtomicLong atom = new AtomicLong(start);
        return t->tester.test(atom.getAndAdd(step),t);
    }
    
    /**
     * 包装一个计数器:计数变量从init开始,每次增加 step
     * 
     * Stream.iterate(0, i->i+1).takeWhile(i_for(6)).forEach(System.out::println);
     * Stream.iterate(0,t->t<6, i->i+1).forEach(System.out::println);
     * 
     * @param n 序列的长度
     * @return Predicate 的谓词判断
     */
    public static <T> Predicate<T> i_for(final long n){
        return i_for(0L, 1L,(i, t)->i<n);
    }
    
    /**
     * 为一个类型为T的流中的每个元素 分配一个索引号，索引号从0开始
     * Key->Value:<br>
     * 0->t1,1->t1,2->t2,...,n-1->tn-1,... <br>
     * NATS(10).map(kvp()).forEach(System.out::println);<br>
     * <br> 
     * 索引号 从0开始
     * @param <T> KVPair 的值类型，这其实就是为一个值 T,分配一个索引号。主要用于对流中的数据进行索引。
     * @return 键值对儿 (long,t) 的生成函数，自动为值匹配一个长整形的编号
     */
    public static <T> Function<T,KVPair<Long,T>> kvp(){
        return kvp(0L);
    }
    
    /**
     * 为一个类型为T的流中的每个元素 分配一个索引号，索引号从start开始
     * Key->Value:<br>
     * start->t0,start+1->t1,start+2->t2,...,start+n-1->tn-1,... <br>
     * NATS(10).map(kvp(0)).forEach(System.out::println);<br>
     * @param <T> KVPair 的值类型，这其实就是为一个值 T,分配一个索引号。主要用于对流中的数据进行索引。
     * @param start 键名索引 的开始位置。
     * @return 键值对儿 (long,t) 的生成函数，自动为值匹配一个长整形的编号
     */
    public static <T> Function<T,KVPair<Long,T>> kvp(final Number start){
        final var atom = new AtomicLong(start.longValue());// 状态缓存：用于生成序号
        return t->new KVPair<>(atom.getAndIncrement(),t);
    }
    
    /**
     * 为一个类型为T的流中的每个元素 分配一个索引号，索引号从0开始
     * Key->Value:<br>
     * 0->t1,1->t1,2->t2,...,n-1->tn-1,... <br>
     * NATS(10).map(kvp_int()).forEach(System.out::println);<br>
     * <br> 
     * 索引号 从0开始
     * @param <T> KVPair 的值类型，这其实就是为一个值 T,分配一个索引号。主要用于对流中的数据进行索引。
     * @return 键值对儿 (int,t) 的生成函数，自动为值匹配一个数型的编号 
     */
    public static <T> Function<T,KVPair<Integer,T>> kvp_int(){
       return kvp_int(0);
    }
    
    /**
     * 为一个类型为T的流中的每个元素 分配一个索引号，索引号从start开始
     * Key->Value:<br>
     * start->t0,start+1->t1,start+2->t2,...,start+n-1->tn-1,... <br>
     * NATS(10).map(kvp_int(0)).forEach(System.out::println);<br>
     * @param <T> KVPair 的值类型，这其实就是为一个值 T,分配一个索引号。主要用于对流中的数据进行索引。
     * @param start 键名索引 的开始位置。
     * @return 键值对儿 (int,t) 的生成函数，自动为值匹配一个整形的编号
     */
    public static <T> Function<T,KVPair<Integer,T>> kvp_int(final Number start){
        return kvp_int(start,e->e);
    }
    
    /**
     * 为一个类型为T的流中的每个元素 分配一个索引号，索引号从start开始 Key->Value:<br>
     * start->t0,start+1->t1,start+2->t2,...,start+n-1->tn-1,... <br>
     * NATS(10).map(kvp_int(0)).forEach(System.out::println);<br>
     * 
     * @param <T>           KVPair 的值类型，这其实就是为一个值 T,分配一个索引号。主要用于对流中的数据进行索引。
     * @param <K>           键类型
     * @param key_generator 键名索引的映射器，把数值类型的序号索引转变成其他的数据类型，<br>
     *                      这个一般用于按照某种key_generator的函数规则来规律的生成K类型。比如 按照列序进行矩阵生成的功能。
     *                      例如：
     *                      nvec.stream(kvp_int(NVec.modeOf(10,1))).sorted((a,b)->a._1().compareTo(b._1()))<br>
     *                      .map(e -> e._2()).collect(aaclc(NVec::new));<br>
     *                      详见 matlib的NVec <br>
     * @return 键值对儿 (int,t) 的生成函数，为值 按照 key_generator 编制一个 K类型 编号
     */
    public static <T, K> Function<T, KVPair<K, T>> kvp_int(final Function<Integer, K> key_generator) {
        return kvp_int(0, key_generator);
    }

    /**
     * 为一个类型为T的流中的每个元素 分配一个索引号，索引号从start开始 Key->Value:<br>
     * start->t0,start+1->t1,start+2->t2,...,start+n-1->tn-1,... <br>
     * NATS(10).map(kvp_int(0)).forEach(System.out::println);<br>
     * 
     * @param <T>           KVPair 的值类型，这其实就是为一个值 T,分配一个索引号。主要用于对流中的数据进行索引。
     * @param <K>           键类型
     * @param start         键名索引 的开始位置。
     * @param key_generator 键名索引的映射器，把数值类型的序号索引转变成其他的数据类型，<br>
     *                      这个一般用于按照某种key_generator的函数规则来规律的生成K类型。比如
     *                      按照列序进行矩阵生成的功能。<br>
     *                      例如：
     *                      nvec.stream(kvp_int(NVec.modeOf(10,1))).sorted((a,b)->a._1().compareTo(b._1()))<br>
     *                      .map(e -> e._2()).collect(aaclc(NVec::new)); <br>
     *                      详见 matlib的NVec <br>
     * @return 键值对儿 (int,t) 的生成函数，为值 按照 key_generator 编制一个 K类型 编号
     */
    public static <T, K> Function<T, KVPair<K, T>> kvp_int(final Number start,
            final Function<Integer, K> key_generator) {
        final var atom = new AtomicInteger(start.intValue());// 状态缓存：用于生成序号
        return t -> new KVPair<>(key_generator.apply(atom.getAndIncrement()), t);
    }

    /**
     * key_generator 根据key 生成 相应的主键。
     * NATS(10).map(kvp(t->t%2)).forEach(System.out::println);
     * 
     * @param <K>           键值名类型
     * @param <T>           键值类型
     * @param key_generator 键变换函数
     * @return 键值对儿 (k,t)
     */
    public static <T, K> Function<T, KVPair<K, T>> kvp(final Function<T, K> key_generator) {
        return t -> new KVPair<>(key_generator.apply(t), t);
    }
    
    /**
     * 列表延展：即构造 全排列的组合。比如：comprehensive([1,2],[a,b]) 会产生：如下结构的数据 <br>
     * 0    1 表头 <br>
     * -------- <br>
     * 1    a 数据项目 <br>
     * 1    b 数据项目 <br>
     * 2    a 数据项目 <br>
     * 2    b 数据项目 <br>
     * 
     * @param ccc 待延展的列表集合。位置向量集合 [cc1,cc2,...] ccc 表示集合的集合即 列表的元素依然是列表
     * @param position 当前工作的位置索引（ccc的元素位置索引），从0开始
     * @param rr 返回结果集合。需要递归累加, r 表示result,rr 象征着 r 的集合。 r 表示record记录的意思。
     */
    public static void _comprehensive( final List<List<?>> ccc, final int position, final List<IRecord> rr ){
        if( ccc==null || ccc.size()<0 || position>=ccc.size() )return;// 保证 参数合法有效。
        
        if(position>=0) {// 位置索引从0开始
            final var cc = ccc.get(position);// 提取当前位置的列表数组
            if(rr.size()==0){// 第一次运行时,rr是一个0长度的List
                cc.forEach(c->rr.add(REC(position,c)));// 初始化构建一个 rr中的每个元素r：REC(position,c),后续将在这个记录结构r上进行扩展
            }else{// 非第一次运行需要对rr中的每个元素进行扩展
                
                // 这是一个写起来有效率，但运行起来没有效率的方法
                //final var aa = LIST(cc.stream().flatMap(c->rr.stream().map(r->REC(position,c).union(r))));// 列表向前展开一层。
                //使用aa内容展开一层后代的结果，替换上一次计算的结果：即模拟:rr = aa的结果，把啊啊赋值与rr
                //rr.clear(); rr.addAll(aa);
                
                // 这是一种运行起来很有效率高：但写起来没有效率的方法,考虑到运行，就采用这种写起来没有效率的算法了。haha 
                final var r_litr = rr.listIterator();// listIterator 带有插入功能,listIterator add 会自动移动itr，保证插入元素后next的指向保持不变。
                while ( r_litr.hasNext() ) { // r_litr 的迭代器
                    final var r_current = r_litr.next();// 待给予展开的元素节点：r_表示元素节点为一个record记录。
                    final var pos = String.valueOf(position);// 当前位置的字符串表示。
                    final var c_itr = cc.iterator();// 当前位置向量（向量就是数组）的元素迭代器
                    r_current.add(pos,c_itr.next());// 使用cc的第一个元素拓展r_current,拓展之后的r_current将成为一个模版,来其余的cc元素（第二个开始）的拓展基础。
                    while (c_itr.hasNext()) {// 用 位置向量cc 中的每个元素(c_itr.next())给予拓展：从第二个元素开始，第一个元素位于循环外侧
                        final var c = c_itr.next();// 待追加到r_current的复制品的 位置向量cc 的元素数据。
                        r_litr.add(r_current.duplicate().set(pos,c));// 用r_current的复制结构duplicate来实现对rr中的元素进行拓展
                    }//while c_itr
                }//while l_itr
                
            }//if if(rr.size()==0)
            
            // 继续向前进行延展
            _comprehensive(ccc,position-1,rr);
        }// 仅当尚未结束。 position>=0
    }
    
    /**
     * 数组的comprehensive
     * @param ccc 待延展的列表集合。ccc 表示集合的集合即 列表的元素依然是列表
     * @return 返回结果集合。需要递归累加
     */
    public static List<IRecord> comprehensive(final List<List<?>> ccc) {
        if(ccc==null || ccc.size()<0)return new LinkedList<>();
        final List<IRecord> rr = new LinkedList<>(); // 构造返回结果集合
        _comprehensive(ccc,ccc.size()-1,rr);
        return rr;
    }
    
    /**
     * comprehensive 的别名
     * 数组的comprehensive
     * @param ccc 待延展的列表集合。ccc 表示集合的集合即 列表的元素依然是列表
     * @return 返回结果集合。需要递归累加
     */
    public static List<IRecord> cph(final List<List<?>> ccc) {
        return comprehensive(ccc);
    }
    
    /**
     * comprehensive 的别名:返回Stream结果
     * 数组的comprehensive
     * @param ccc 待延展的列表集合。ccc 表示集合的集合即 列表的元素依然是列表
     * @return 返回结果集合。需要递归累加
     */
    public static Stream<IRecord> cph2(final List<List<?>> ccc) {
        return comprehensive(ccc).stream();
    }
    
    /**
     * comprehensive 的别名
     * 数组的comprehensive
     * @param ccc 待延展的列表集合。ccc 表示集合的集合即 列表的元素依然是列表
     * @return 返回结果集合。需要递归累加
     */
    public static List<IRecord> cph(final Stream<List<?>> ccc) {
        return comprehensive(LIST(ccc));
    }
    
    /**
     * 数组的comprehensive
     * @param ccc 待延展的列表集合。
     * @return 返回结果集合。需要递归累加
     */
    public static List<IRecord> comprehensive(final List<?> ... ccc) {
        if(ccc==null || ccc.length<0)return new LinkedList<>();
        final List<IRecord> rr = new LinkedList<>(); // 构造返回结果集合
        _comprehensive(Arrays.asList(ccc),ccc.length-1,rr);
        return rr;
    }
    
    /**
     * comprehensive 的别名
     * @param ccc 待延展的列表集合。
     * @return 返回结果集合。需要递归累加
     */
    public static List<IRecord> cph(final List<?> ... ccc) {
        return comprehensive((List<?>[])ccc);
    }
    
    /**
     * comprehensive(LittleTree::NN,"1:10:2") 示例程序
     * 数组的comprehensive
     * 用法示例
     * comprehensive(s->s.split(","),"1,2,3,4","a,b,c,d").forEach(System.out::println);
     * 
     * @param <S> 源数据类型
     * @param <T> 目标的数据元素类型 
     * @param parser S对象解析函数
     * @param ss 数据源集合。
     * @return List<IRecord> 结构的元素 结合
     */
    @SafeVarargs
    public static <S,T> List<IRecord> comprehensive(final Function<S,T[]> parser, final S...ss) {
        final List<List<?>> ccc= LIST(Arrays.stream(ss).map(parser).map(Arrays::asList));
        return comprehensive(ccc);
    }
    
    /**
     * comprehensive 的别名
     * comprehensive(LittleTree::NN,"1:10:2") 示例程序
     * 数组的comprehensive
     * 用法示例
     * comprehensive(s->s.split(","),"1,2,3,4","a,b,c,d").forEach(System.out::println);
     * 
     * @param <S> 源数据类型
     * @param <T> 目标的数据元素类型 
     * @param parser S对象解析函数
     * @param ss 数据源集合。
     * @return List<IRecord> 结构的元素 结合
     */
    @SafeVarargs
    public static <S,T> List<IRecord> cph(final Function<S,T[]> parser,final S...ss) {
        return comprehensive(parser,(S[])ss);
    }
    
    /**
     * comprehensive 的别名  <br>
     * comprehensive(LittleTree::NN,"1:10:2") 示例程序 <br>
     * 数组的comprehensive  <br>
     * 用法示例  <br>
     * comprehensive(s->s.split(","),"1,2,3,4","a,b,c,d").forEach(System.out::println);  <br>
     * 
     * @param <S> 源数据类型
     * @param <T> 目标的数据元素类型
     * @param parser S对象解析函数
     * @param ss 数据源集合。
     * @return Stream<IRecord> 结构的IRecord流 ，每个IRecord元素是倒序的。
     */
    @SafeVarargs
    public static <S,T> Stream<IRecord> cph2(final Function<S,T[]> parser,final S...ss) {
        return comprehensive(parser,(S[])ss).stream().map(IRecord::reverse);
    }
    
    /**
     * 数组的comprehensive
     * @param ccc 待延展的列表集合。
     * @return 返回全排列的结果  IRecord集合的流。
     */
    public static List<IRecord> comprehensive(final Object[] ... ccc) {
        if(ccc==null || ccc.length<0)return new LinkedList<>();
        final List<IRecord> rr = new LinkedList<>();
        final List<List<?>> lll = new LinkedList<>();
        for(var cc:ccc)lll.add(Arrays.asList(cc));
        _comprehensive(lll,ccc.length-1,rr);
        return rr;
    }
    
    /**
     * comprehensive 的别名，对ccc 中的集合元素进行全排列。
     * @param ccc 待延展的列表集合。
     * @return 返回全排列的结果  IRecord集合的流。
     */
    public static List<IRecord> cph(final Object[] ... ccc) {
        return comprehensive((Object[][])ccc);
    }
    
    /**
     * comprehensive 的别名,对ccc 中的集合元素进行全排列。<br>
     * 对排列结果，采用reverse以维持原有谁能够。<br>
     * @param <T> 参数的对象类型 使用泛型以保证对 任意类型的接收
     * @param ccc 待延展的列表集合。需要注意ccc 需要是一个T[][]。写成 T[] ... ccc 是为了保证不定参数。
     * @return 返回全排列的结果  IRecord集合的流。
     */
    @SafeVarargs
    public static <T> Stream<IRecord> cph2(final T[] ... ccc) {
        return comprehensive((Object[][])ccc).stream().map(IRecord::reverse);
    }
    
    /**
     * comprehensive 的别名,对ccc 中的集合元素进行全排列。<br>
     * 对排列结果，采用reverse以维持原有谁能够。<br>
     * @param <T> 参数的对象类型 使用泛型以保证对 任意类型的接收
     * @param ccc 待延展的列表集合。需要注意ccc 需要是一个T[][]。写成 T[] ... ccc 是为了保证不定参数。
     * @return 返回全排列的结果  IRecord集合的流。
     */
    @SuppressWarnings("unchecked")
    @SafeVarargs
    public static <T> Stream<IRecord> cph2(final List<T> ... ccc) {
        return comprehensive((List<List<?>>)(Object)Arrays.asList(ccc)).stream();// 注意一定需要用List<List<?>>来完成类型转换，否则会接入到错误类型。
    }
    
    /**
     * 可以抛出异常的函数
     * @author gbench
     *
     * @param <T> 源数据类型
     * @param <U> 结果数据类型
     */
    @FunctionalInterface
    public interface ExceptionalFunction<T,U>{
        /**
         * 函数调用函数
         * @param t 函数参数
         * @return U类型的函数
         * @throws Exception 异常
         * @throws Throwable 抛出物
         */
        U apply(T t) throws Exception,Throwable;
    };
    
    /**
     * 可以抛出异常的消费函数
     * @author gbench
     *
     * @param <T> 源数据类型
     */
    @FunctionalInterface
    public interface ExceptionConsumer<T>{
        /**
         * 数据消费函数
         * @param t 函数参数
         * @return U类型的函数
         * @throws Exception 异常
         * @throws Throwable 抛出物
         */
        void accept(T t) throws Exception,Throwable;
    };

    /**
     * 构造出一个可以捕获抛出异常的一元函数 <br>
     * 
     * 用法示例：<br>
     * Stream.of("trycach用法示例").forEach(line->{ // 书写一行数据 <br>
     *    final var constructor = compose_ef(BufferedWriter::new,(ExceptionalFunction<String,FileWriter>)FileWriter::new);// 构造函数  <br>
     *    final var bw = Optional.of("d:/sliced/tmp/a.txt").map(trycatch(constructor)).get();// 创建书写器  <br>
     *    Stream.of(bw).forEach(trycatch2(writer->writer.append(line)));// 书写内容  <br>
     *    Stream.of(bw).forEach(trycatch3(Writer::close)); // 关闭书写器  <br>
     * });  <br>
     * 
     * @param <T> 源数据类型
     * @param <U> 解雇数据类型
     * @param exceptionFunction 一个可以抛出异常的函数
     * @return 剥夺掉异常的函数
     */
    public static <T, U> Function<T, U> trycatch( final ExceptionalFunction<T, U> exceptionFunction) {
        
        return t -> {
            try {
                return exceptionFunction.apply(t);
            } catch (Exception e) {
                e.printStackTrace();
            } catch (Throwable e) {
                e.printStackTrace();
            } // try// try
            
            return null;
        };// 返回一个Function
    }
    
    /**
     * 构造出一个可以捕获抛出异常的一元消费函数 <br>
     * 用法示例：<br>
     * Stream.of("trycach用法示例").forEach(line->{ // 书写一行数据 <br>
     *    final var constructor = compose_ef(BufferedWriter::new,(ExceptionalFunction<String,FileWriter>)FileWriter::new);// 构造函数  <br>
     *    final var bw = Optional.of("d:/sliced/tmp/a.txt").map(trycatch(constructor)).get();// 创建书写器  <br>
     *    Stream.of(bw).forEach(trycatch2(writer->writer.append(line)));// 书写内容  <br>
     *    Stream.of(bw).forEach(trycatch3(Writer::close)); // 关闭书写器  <br>
     * });  <br>
     * 
     * @param <T> 源数据类型
     * @param exceptionFunction 一个可以抛出异常的函数
     * @return 剥夺掉异常的函数
     */
    public static <T> Consumer<T> trycatch2(final ExceptionalFunction<T, ?> exceptionFunction){
        return fun2cs(trycatch(exceptionFunction));
    }
    
    /**
     * 构造出一个可以捕获抛出异常的一元消费函数 <br>
     * 用法示例：<br>
     * Stream.of("trycach用法示例").forEach(line->{ // 书写一行数据 <br>
     *    final var constructor = compose_ef(BufferedWriter::new,(ExceptionalFunction<String,FileWriter>)FileWriter::new);// 构造函数  <br>
     *    final var bw = Optional.of("d:/sliced/tmp/a.txt").map(trycatch(constructor)).get();// 创建书写器  <br>
     *    Stream.of(bw).forEach(trycatch2(writer->writer.append(line)));// 书写内容  <br>
     *    Stream.of(bw).forEach(trycatch3(Writer::close)); // 关闭书写器  <br>
     * });  <br>
     * 
     * @param <T> 源数据类型
     * @param exceptioncs 一个可以抛出异常的 消费函数
     * @return 剥夺掉异常的函数
     */
    public static <T> Consumer<T> trycatch3(final ExceptionConsumer<T> exceptioncs){
        return t->{
            try{
                exceptioncs.accept(t);
            } catch(Throwable e) {
                e.printStackTrace();
            }
        };
    }
    
    /**
     * 把一个函数转换成消费函数
     * @param <T> 源数据类型
     * @param func 一个T为参数的一元函数
     * @return 消费函数 cosnumer&lt;T&gt;
     */
    public static <T> Consumer<T> fun2cs(Function<T,?> func){
        return func::apply;
    }
    
    /**
     * 组合两个函数 <br>
     * @param <T> 第一个参数类型
     * @param <U> 第二个参数类型
     * @param <V> 第三个参数类型
     * @param ftu t->u
     * @param fuv u->v
     * @return t->v
     */
    public static <T,U,V> Function<T,V> compose_f(final Function<U,V> fuv, final Function<T,U> ftu){
        return fuv.compose(ftu);
    }
    
    /**
     * 组合三个函数 <br>
     * @param <T> 第一个参数类型
     * @param <U> 第二个参数类型
     * @param <V> 第三个参数类型
     * @param <X> 第四个参数类型
     * @param ftu t->u
     * @param fuv u->v
     * @param fvx v->x
     * @return t->x
     */
    public static <T,U,V,X> Function<T,X> compose_f(final Function<V,X> fvx,final Function<U,V> fuv, final Function<T,U> ftu){
        return fvx.compose(fuv.compose(ftu));
    }
    
    /**
     * 组合四个函数 <br>
     * @param <T> 第一个参数类型
     * @param <U> 第二个参数类型
     * @param <V> 第三个参数类型
     * @param <X> 第四个参数类型
     * @param <Y> 第五个参数类型
     * @param ftu t->u
     * @param fuv u->v
     * @param fvx v->x
     * @param fxy x->y
     * @return t->y
     */
    public static <T,U,V,X,Y> Function<T,Y> compose_f(final Function<X,Y> fxy,final Function<V,X> fvx,final Function<U,V> fuv, final Function<T,U> ftu){
        return fxy.compose(fvx.compose(fuv.compose(ftu)));
    }
    
    /**
     * 组合五个个函数 <br>
     * @param <T> 第一个参数类型
     * @param <U> 第二个参数类型
     * @param <V> 第三个参数类型
     * @param <X> 第四个参数类型
     * @param <Y> 第五个参数类型
     * @param <Y> 第六个参数类型
     * @param <Z> 第七个参数类型
     * @param ftu t->u
     * @param fuv u->v
     * @param fvx v->x
     * @param fxy x->y
     * @param fyz y->z
     * @return t->z
     */
    public static <T,U,V,X,Y,Z> Function<T,Z> compose_f(final Function<Y,Z> fyz,final Function<X,Y> fxy,final Function<V,X> fvx,final Function<U,V> fuv, final Function<T,U> ftu){
        return fyz.compose(fxy.compose(fvx.compose(fuv.compose(ftu))));
    }
    
    /**
     * 组合成一个消费函数
     * @param <T> 第一个参数类型
     * @param <U> 第二个参数类型
     * @param ftu t->u
     * @param cs u->{}
     * @return t->{}
     */
    public static <T,U> Consumer<T> compose_cs(final Consumer<U> cs, final Function<T,U> ftu){
        return t->cs.accept(ftu.apply(t));
    }
    
    /**
     * 组合两个函数 <br>
     * 
     * 用法示例：<br>
     * Stream.of("trycach用法示例").forEach(line->{ // 书写一行数据 <br>
     *    final var constructor = compose_ef(BufferedWriter::new,(ExceptionalFunction<String,FileWriter>)FileWriter::new);// 构造函数  <br>
     *    final var bw = Optional.of("d:/sliced/tmp/a.txt").map(trycatch(constructor)).get();// 创建书写器  <br>
     *    Stream.of(bw).forEach(trycatch2(writer->writer.append(line)));// 书写内容  <br>
     *    Stream.of(bw).forEach(trycatch3(Writer::close)); // 关闭书写器  <br>
     * });  <br>
     * 
     * @param <T> 第一个参数类型
     * @param <U> 第二个参数类型
     * @param <V> 第三个参数类型
     * @param ftu t->u
     * @param fuv u->v
     * @return t->v
     */
    public static <T,U,V> ExceptionalFunction<T,V> compose_ef(final ExceptionalFunction<U,V> fuv, final ExceptionalFunction<T,U> ftu){
        return t->fuv.apply(ftu.apply(t));
    }
    
    /**
     * 对 一个  line 进行分词
     * @param line 数据字符串
     * @param keywords 关键词列表
     * @return 分词结果 {name:分词符号,flag:分词标记是 keyword为true否自false,offset:偏移量}
     */
    public static List<IRecord> tokenize(final String line, final List<String> keywords) {
        final Function<String,List<Character>> lc = strline -> strline.chars().mapToObj(c->(char)c)
            .collect(Collectors.toList());// 把一个字符串转换成一个字符列表
        final var keywordsTrie = new TrieNode<>('/');// 前缀树
        keywords.stream().map(lc).forEach(keywordsTrie::addWord);// 构建前赘树
        return tokenize(line,keywordsTrie);
    }// tokenize
    
    /**
     * 对 一个  源数据字符串line 进行分词,分词列表 是 IRecord 列表[{name:分词符号,flag:分词标记是 keyword为true否自false,offset:偏移量}]
     * @param line 源数据数据字符串
     * @param keywordsTrie 以 '/' 为根节点的 keywords前缀树  
     * @return 分词结果 {name:分词符号,flag:分词标记是 keyword为true否自false,offset:偏移量}
     */
    public static List<IRecord> tokenize(final String line, final TrieNode<Character> keywordsTrie) {
        final Function<String,List<Character>> lc = strline -> strline.chars().mapToObj(c->(char)c)
            .collect(Collectors.toList());// 把一个字符串转换成一个字符列表
        final var len = line.length();// 模版字符串的长度。
        final var stack = new Stack<String>();// 候选集合：即当前业已发现匹配的 候选keyword集合。 最长的候选keyword位于栈顶最短的位于栈底。
        int i = 0;// 当前阶段/周期  读取的模版字符位置。即开始位置。
        final var tokens = new LinkedList<IRecord>(); // 分词结果的集合。
        
        while( i<len ) {// 逐字读取
            stack.clear();// 清空候选集合
            int j = i;// 读取串的结束位置(不包含)。阶段/周期 开始位置 开始。读取串由[i,j)来进行定义。
            var prefixNode = keywordsTrie.getNode(Arrays.asList('/',line.charAt(i)));// 前缀节点:i周期初始前缀节点。
            
            // 在i周期初始前缀节点的基础之上,使用 while循环逐增加字符使之成为keyword(最长)以提取keyword.
            while( prefixNode!=null ) {// 尽力向前读取字符直到不是前缀为止:尝试在从当前位置开始向后读取占位符，尽可能长的读取字符。直到不能够拼成占位付的前缀为止。
                if(prefixNode.flag()) stack.push(prefixNode.path());
                if(j==len) break;
                prefixNode = keywordsTrie.getNode(lc.apply("/"+line.substring(i, ++j)));// 移动读取位置的右侧索引。
            }//while prefixNode!=null
            
            if( !stack.empty() ) { // 已经发现了keyword
                final var keyword = stack.pop();// 提取最长的即栈顶元素作为keyword。
                tokens.add(REC("name",keyword,"flag",true,"offset",i)); // 为防止 两个连续keyword,不能把keyword后面的读取的字符视为普通word即flag为false的字符串。
                i+=keyword.length();// 步长移动keyword长度。
            }else { // word template的子串[i,j)表示模版内容则给予拷贝buffer缓存,即比keywords的前缀多一个非前缀字符的字符串。
                final var word = line.substring(i,j==i?i+1:j);// 读取的单词,因为在  while( prefixNode!=null ) 跳出循环前做过 ++j,座椅这里只用使用j
                tokens.add(REC("name",word,"flag",false,"offset",i));// 提取业已读取的(j位置的字符已经读取）字符串长度。
                i+=word.length();// 步长移动到word长度
            }// !stack.empty()
            
        }// while i<len
        
        return tokens; // 返回结果
    }// tokenize
    
    public static boolean debug = false;// 调试信息开启标记
    
}
